xanoutas/solidity-security-findings huggingface dataset:
User can drain the rewards pool 
Audit: 2023-05-maia-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/talos/boost-aggregator/BoostAggregator.sol#L109-L136


# Vulnerability details

## Impact
In the ```BoostAggregator.sol``` a malicious user can use a call to ```unstakeAndWithdraw(...)``` to drain the rewards pool leading to a loss of funds.


## Proof of Concept
After ```rewards``` have been claimed by the user, the ```tokenIdRewards[tokenId]``` which is the  rewards that have been previously settled or claimed for the ```tokenId``` position is not updated. The user can restake the position and call ```unstakeAndWithdraw(...)```. The cycle is repeated by the malicious user until the rewards pool is empty.

```
    function unstakeAndWithdraw(uint256 tokenId) external {
        ...

        uint256 pendingRewards = uniswapV3Staker.tokenIdRewards(tokenId) - tokenIdRewards[tokenId];

        if (pendingRewards > DIVISIONER) {
            ...
            pendingRewards -= newProtocolRewards;
            address rewardsDepot = userToRewardsDepot[user];
            if (rewardsDepot != address(0)) {
                uniswapV3Staker.claimReward(rewardsDepot, pendingRewards);
            } else {
                uniswapV3Staker.claimReward(user, pendingRewards);
            }
        }
        uniswapV3Staker.withdrawToken(tokenId, user, "");
    }
```

Subsequent calls to ```unstakeAndWithdraw(...)``` will be using an outdated value for ```tokenIdRewards[tokenId]``` which will lead to pending rewards getting larger
```
uint256 pendingRewards = uniswapV3Staker.tokenIdRewards(tokenId) - tokenIdRewards[tokenId];
```


## Tools Used
Manual Review


## Recommended Mitigation Steps
Add logic to update ```tokenIdRewards[tokenId]``` before withdrawing the tokenId position

```
    function unstakeAndWithdraw(uint256 tokenId) external {
        ...

        uint256 pendingRewards = uniswapV3Staker.tokenIdRewards(tokenId) - tokenIdRewards[tokenId];

        if (pendingRewards > DIVISIONER) {
            ...
            pendingRewards -= newProtocolRewards;
            address rewardsDepot = userToRewardsDepot[user];

        }
        tokenIdRewards[tokenId] += pendingRewards; // perform update here.
        uniswapV3Staker.withdrawToken(tokenId, user, "");
    }
```


## Assessed type

Other
owner can add reward token to zero address.
Audit: 2023-05-maia-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/rewards/depots/MultiRewardsDepot.sol#L47-L54


# Vulnerability details

## Impact
In the ```MultiRewardsDepot.sol``` contract, a call to ```addAsset(...)``` owner can add reward token to zero address leading to funds being lost forever.

## Proof of Concept
If a zero address is entered for ```rewardsContract(...)```, funds could be locked forever.

```
    function addAsset(address rewardsContract, address asset) external onlyOwner {

        if (_isAsset[asset] || _isRewardsContract[rewardsContract]) revert ErrorAddingAsset();
        _isAsset[asset] = true;
        _isRewardsContract[rewardsContract] = true;
        _assets[rewardsContract] = asset;


        emit AssetAdded(rewardsContract, asset);
    }
```



## Tools Used
Manual Review

## Recommended Mitigation Steps
Add a check for zero address
```
require(rewardsContract != address(0), "...")
```

```
    function addAsset(address rewardsContract, address asset) external onlyOwner {
        require(rewardsContract != address(0), "...")
        if (_isAsset[asset] || _isRewardsContract[rewardsContract]) revert ErrorAddingAsset();

        ...
        emit AssetAdded(rewardsContract, asset);
    }
```


## Assessed type

Other
Incorrect implementation of claimGovernance
Audit: 2023-05-maia-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/maia/PartnerUtilityManager.sol#L147-L152
https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/maia/PartnerUtilityManager.sol#L150-L152


# Vulnerability details

## Impact
In the current implementation of ```claimGovernance(...)``` in the ```PartnerUtilityManager.sol``` contract, user can claim more boost than is available.

## Proof of Concept
In the line below, 
```
        if (governanceAvailable < amount) {
            IBaseVault(partnerVault).clearWeight(amount - governanceAvailable);
        }
```
the function first checks that the amount of boost to be claimed is more than the available boost. 

Consider this scenario
```
amount = 9unit, 
governanceAvailable = 4units 
=> amount - governanceAvailable = 5units
```

## Tools Used
Manual review

## Recommended Mitigation Steps
Ensure that the ```amount``` to claim is less than or equal to the ```governanceAvailable```. And in a situation where the ```amount``` is more than the ```governanceAvailable```, cap the withdrawal at the ```governanceAvailable```. 

```
if (amount <= governanceAvailable){
   IBaseVault(partnerVault).clearBoost(amount);
} else {
   IBaseVault(partnerVault).clearBoost(governanceAvailable);
}
```




## Assessed type

Other
Incorrect implementation of claimWeight
Audit: 2023-05-maia-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/maia/PartnerUtilityManager.sol#L127-L135
https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/maia/PartnerUtilityManager.sol#L130-L132


# Vulnerability details

## Impact
In the current implementation of ```claimWeight(...)``` in the ```PartnerUtilityManager.sol``` contract, user can claim more boost than is available.

## Proof of Concept
In the line below, 
```
        if (weightAvailable < amount) {
            IBaseVault(partnerVault).clearWeight(amount - weightAvailable);
        }
```
the function first checks that the amount of boost to be claimed is more than the available boost. 

Consider this scenario
```
amount = 9unit, 
weightAvailable = 4units 
=> amount - weightAvailable = 5units
```

## Tools Used
Manual review

## Recommended Mitigation Steps
Ensure that the ```amount``` to claim is less than or equal to the ```weightAvailable```. And in a situation where the ```amount``` is more than the ```weightAvailable```, cap the withdrawal at the ```weightAvailable```. 

```
if (amount <= weightAvailable){
   IBaseVault(partnerVault).clearBoost(amount);
} else {
   IBaseVault(partnerVault).clearBoost(weightAvailable);
}
```






## Assessed type

Other
Not using slippage parameter in swap() while swapping causes loss of funds
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/talos/libraries/PoolActions.sol#L46-L52


# Vulnerability details

## Impact
While making a swap on UniswapV3 the caller should use the slippage parameter amountOutMinimum parameter to avoid losing funds.

In swapToEqualAmounts() does not use the slippage parameter amountOutMinimum.

```Solidity
File: /src/talos/libraries/PoolActions.sol#L46-L52

    function swapToEqualAmounts(ActionParams memory actionParams, int24 baseThreshold) internal {
        (bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96) = actionParams
            .pool
            .getSwapToEqualAmountsParams(
            actionParams.optimizer, actionParams.tickSpacing, baseThreshold, actionParams.token0, actionParams.token1
        );

        //Swap imbalanced token as long as we haven't used the entire amountSpecified and haven't reached the price limit
        actionParams.pool.swap(
            address(this),
            zeroForOne,
            amountSpecified,
            sqrtPriceLimitX96,
            abi.encode(SwapCallbackData({zeroForOne: zeroForOne}))
        );
    }
```


amountOutMinimum is used to specify the minimum amount of tokens the caller wants to be returned from a swap. Using amountOutMinimum tells the swap that the caller will accept a minimum amount of output tokens from the swap, opening up the user to a catastrophic loss of funds via MEV bot sandwich attacks.


## Proof of Concept
https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/talos/libraries/PoolActions.sol#L46-L52

## Tools Used
Manual review

## Recommended Mitigation Steps
Use/Introduce parameters amountOutMinimum to avoid loss of funds.


## Assessed type

Other
Potential Loss of Funds Due to Zero Slippage Hardcoding in TalosBaseStrategy#deposit
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/talos/base/TalosBaseStrategy.sol#L206-L207


# Vulnerability details


## Impact
In the deposit function within the TalosBaseStrategy contract, both slippage for two tokens (amount0Min and amount1Min) are hardcoded to zero. This can have severe implications as users may unintentionally accept a minimum of zero output tokens from a swap.

## Proof of Concept
https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/talos/base/TalosBaseStrategy.sol#L206-L207. 

As seen here, the hardcoding of zero slippage could potentially result in significant losses for users due to receiving no output tokens from the swap.

## Tools Used
Manual Review

## Recommended Mitigation Steps

It is advised to enable users to specify their preferred slippage. This will provide users with greater control  reducing the risk of unexpected losses due to accepting swaps with no output tokens.


## Assessed type

Other
MALICIOUS USER CAN CALL THE `FlywheelBribeRewards.setRewardsDepot()` FUNCTION INDEFINITELY TO PUSH `ethereum` INTO `STATE BLOAT`
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/main/src/rewards/rewards/FlywheelBribeRewards.sol#L37-L42


# Vulnerability details

## Impact
The `FlywheelBribeRewards.setRewardsDepot()` function is an external permissionless function. Any malicious user can create as many ERC20 compatible contracts as possible and can call this function to set themselves as `strategies` in the `FlywheelBribeRewards.rewardsDepots` mapping. Hence this could be used to add as many instances as possible to the `rewardsDepots` state variable. Hence this can be used by a malicious user to increase the `storage` used by the smart contract which could lead to `state bloat` in the `ethereum` state.

## Proof of Concept

```solidity
    function setRewardsDepot(RewardsDepot rewardsDepot) external {
        /// @dev Anyone can call this, whitelisting is handled in FlywheelCore
        rewardsDepots[ERC20(msg.sender)] = rewardsDepot;

        emit AddRewardsDepot(msg.sender, rewardsDepot);
    }
```

https://github.com/code-423n4/2023-05-maia/blob/main/src/rewards/rewards/FlywheelBribeRewards.sol#L37-L42

## Tools Used
VSCode and Manual Review

## Recommended Mitigation Steps

It is recommended to keep an `upperbound` to the number of `rewardsDepot` that can be added to the `rewardsDepots` mapping via the `FlywheelBribeRewards.setRewardsDepot` function. This can be done by maintaining an incrementer inside the `FlywheelBribeRewards.setRewardsDepot` function, which will increment each time a new `rewardsDepot` is added to the mapping. A check should performed inside the `setRewardsDepot` to make sure this incrementer value is less than the `upperbound` set. `upperbound` can be set as a `constant` and the `incrementer` can be set as a state variable. The `setRewardsDepot` transaction should revert if the `incrementer` exceeds the `upperbound`. This will prevent state `mapping` expanding unnecessarily and forcing the `ethereum` into `state bloat`.


## Assessed type

Other
Slippage controls for calling `bHermes` contract's `ERC4626DepositOnly.deposit` and `ERC4626DepositOnly.mint` functions are missing
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/53c7fe9d5e55754960eafe936b6cb592773d614c/src/erc-4626/ERC4626DepositOnly.sol#L32-L44
https://github.com/code-423n4/2023-05-maia/blob/53c7fe9d5e55754960eafe936b6cb592773d614c/src/erc-4626/ERC4626DepositOnly.sol#L47-L58
https://github.com/code-423n4/2023-05-maia/blob/53c7fe9d5e55754960eafe936b6cb592773d614c/src/ulysses-amm/UlyssesRouter.sol#L49-L56


# Vulnerability details

## Impact
https://eips.ethereum.org/EIPS/eip-4626#security-considerations mentions that "if implementors intend to support EOA account access directly, they should consider adding an additional function call for `deposit`/`mint`/`withdraw`/`redeem` with the means to accommodate slippage loss or unexpected deposit/withdrawal limits, since they have no other means to revert the transaction if the exact output amount is not achieved." Using the `bHermes` contract that inherits the `ERC4626DepositOnly` contract, EOAs can call the following `ERC4626DepositOnly.deposit` and `ERC4626DepositOnly.mint` functions directly. However, because no slippage controls can be specified when calling these functions, these functions' `shares` and `assets` outputs can be less than expected to these EOAs.

https://github.com/code-423n4/2023-05-maia/blob/53c7fe9d5e55754960eafe936b6cb592773d614c/src/erc-4626/ERC4626DepositOnly.sol#L32-L44
```solidity
    function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) {
        // Check for rounding error since we round down in previewDeposit.
        require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");

        // Need to transfer before minting or ERC777s could reenter.
        address(asset).safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }
```

https://github.com/code-423n4/2023-05-maia/blob/53c7fe9d5e55754960eafe936b6cb592773d614c/src/erc-4626/ERC4626DepositOnly.sol#L47-L58
```solidity
    function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) {
        assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up.

        // Need to transfer before minting or ERC777s could reenter.
        address(asset).safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }
```

In contrast, the following `UlyssesRouter.addLiquidity` function does control the slippage by including the `minOutput` input and executing `amount = ulysses.deposit(amount, msg.sender)` and `if (amount < minOutput) revert OutputTooLow()`. Although such slippage control for an ERC-4626 vault exists in this protocol's other contract, it does not exist in the `bHermes` contract. As a result, EOAs can mint less bHermes shares than expected when calling
Missing deadline checks allow pending transactions to be maliciously executed
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/talos/libraries/PoolActions.sol#L46-L52


# Vulnerability details

## Impact
In PoolActions.sol, swapToEqualAmounts() function has no deadline check for the transaction when swapping.

```Solidity
File: src/talos/libraries/PoolActions.sol

    function swapToEqualAmounts(ActionParams memory actionParams, int24 baseThreshold) internal {
        (bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96) = actionParams
            .pool
            .getSwapToEqualAmountsParams(
            actionParams.optimizer, actionParams.tickSpacing, baseThreshold, actionParams.token0, actionParams.token1
        );

        //Swap imbalanced token as long as we haven't used the entire amountSpecified and haven't reached the price limit
        actionParams.pool.swap(
            address(this),
            zeroForOne,
            amountSpecified,
            sqrtPriceLimitX96,
            abi.encode(SwapCallbackData({zeroForOne: zeroForOne}))
        );
    }
```

AMMs provide their users with an option to limit the execution of their pending actions, such as swaps or adding and removing liquidity. The most common solution is to include a deadline timestamp as a parameter (for example see Uniswap V2 and Uniswap V3). If such an option is not present, users can unknowingly perform bad trades:

1) Alice wants to swap 100 tokens for 1 ETH and later sell the 1 ETH for 1000 DAI.
2) The transaction is submitted to the mempool, however, Alice chose a transaction fee that is too low for miners to be interested in including her transaction in a block. The transaction stays pending in the mempool for extended periods, which could be hours, days, weeks, or even longer.
3) When the average gas fee dropped far enough for Alice’s transaction to become interesting again for miners to include it, her swap will be executed. In the meantime, the price of ETH could have drastically changed. She will still get 1 ETH but the DAI value of that output might be significantly lower. She has unknowingly performed a bad trade due to the pending transaction she forgot about.

An even worse way this issue can be maliciously exploited is through MEV:

1) The swap transaction is still pending in the mempool. Average fees are still too high for miners to be interested in it. The price of tokens has gone up significantly since the transaction was signed, meaning Alice would receive a lot more ETH when the swap is executed. But that also means that her maximum slippage value (sqrtPriceLimitX96 and minOut in terms of the Spell contracts) is outdated and would allow for significant slippage.
2) A MEV bot detects the pending transaction. Since the outdated maximum slippage value now allows for high slippage, the bot sandwiches Alice, resulting in significant profit for the bot and significant loss for Alice.

## Proof of Concept
https://github.com/code-423n4/2023-05-maia/blob/cfed
Vulnerable to MEV exploitation due to lack of slippage protection
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L353-L361
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolActions.sol#L73-L87
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L201-L212


# Vulnerability details

## Proof of Concept

Function to decrease and increase liquidity are passing `amount0Min` and `amount1Min` as zero. This will result in MEV bots sandwiching transactions to extract value from it. In the worst case it will actually return zero or a very small value in wei, and the funds will be lost.

https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L353-L361

https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolActions.sol#L73-L87

Note that `TalosBaseStrategy.deposit()` will check the returned `amount0` and `amount1` are not zero. However, bots may return a small value like 1 wei, which would make the check pass and the value is still virtually zero.

```
(liquidityDifference, amount0, amount1) = nonfungiblePositionManager.increaseLiquidity(
    INonfungiblePositionManager.IncreaseLiquidityParams({
        tokenId: _tokenId,
        amount0Desired: amount0Desired,
        amount1Desired: amount1Desired,
        amount0Min: 0,
        amount1Min: 0,
        deadline: block.timestamp
    })
);

if (amount0 == 0 && amount1 == 0) revert AmountsAreZero();
```

https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L201-L212

## Impact

The likelihood of this issue taking place is high since MEV boots are widely deployed on EVM chains. The impact is also high since it will most likely result in losing funds/assets.

## Tools Used

Manual review.

## Recommended Mitigation Steps

Consider calculating a min amount to be used on `amount0Min` and `amount1Min`. Alternatively, consider adding input params so that the caller can choose `amount0Min` and `amount1Min`.



## Assessed type

MEV
Calculation during rebalancing can overflow
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolVariables.sol#L231-L252


# Vulnerability details

## Proof of Concept

Rebalancing logic in `TalosBaseStrategy` will start by the strategy manager calling `TalosBaseStrategy.rebalance()` to swap imbalanced tokens. This function will call `TalosStrategySimple.doRebalance()`

https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L317

Next, `PoolActions.swapEqualAmounts()` will be called.

https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/strategies/TalosStrategySimple.sol#L42

Finally, `PoolVariables.getSwapToEqualAmountsParams()` will be called to calculate the amounts base of ticks from the uniswap v3 pool.

```
(bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96) = actionParams
    .pool
    .getSwapToEqualAmountsParams(
    actionParams.optimizer, actionParams.tickSpacing, baseThreshold, actionParams.token0, actionParams.token1
);
```

https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolActions.sol#L41

The issue is that `sqrtPriceX96` in `PoolVariables.getSwapToEqualAmountsParams()` can overflow.

```
(uint160 sqrtPriceX96, int24 currentTick,,,,,) = _pool.slot0();
```

https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolVariables.sol#L231-L252

We can see that Uniswap `getQuoteAtTicks()` [handles](https://github.com/Uniswap/v3-periphery/blob/main/contracts/libraries/OracleLibrary.sol#L58) the case for `sqrtRatioX96 <= type(uint128).max`.

## Impact

Aside from `sqrtPriceX96` being subject to overflow, it's also possible for `sqrtPriceX96` to be smaller than 128 bits but to `exactSqrtPriceImpact` to overflow since it's being multiplied by `_strategy.priceImpactPercentage()` and the resulting value will be incremented or decremented depending on `zeroForOne`.

```
uint160 exactSqrtPriceImpact = (sqrtPriceX96 * (_strategy.priceImpactPercentage() / 2)) / GLOBAL_DIVISIONER;
sqrtPriceLimitX96 = zeroForOne ? sqrtPriceX96 - exactSqrtPriceImpact : sqrtPriceX96 + exactSqrtPriceImpact;
```

https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolVariables.sol#L251-L252

On either case, the value returned by `PoolVariables.getSwapToEqualAmountsParams()` will be wrong and strategies might be rebalanced incorrectly since an incorrect `sqrtPriceLimitX96` would be passed to `pool.swap`.

```
actionParams.pool.swap(
    address(this),
    zeroForOne,
    amountSpecified,
    sqrtPriceLimitX96,
    abi.encode(SwapCallbackData({zeroForOne: zeroForOne}))
);
```

https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolActions.sol#L46-L52

## Tools Used

Manual review.

## Recommended Mitigation Steps

Account for potential overflow in `sqrtPriceX96` and `exactSqrtPriceImpact` inside `PoolVariables.getSwapToEqualAmountsParams()`.



## Assessed type

Under/Overflow