xanoutas/solidity-security-findings huggingface dataset:
Owner can reduce Governance power of a user
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/main/src/hermes/tokens/bHermesVotes.sol#L36


# Vulnerability details

## Impact

The owner of contract can accidently or acting maliciously can burn a user bHermes gauge tokens. This will affect the governance power of others, as it can be used in increasing weighting power for oneself by minting more tokens and decreasing others to pass any proposal by overtaking the project.

## Proof of Concept
https://github.com/code-423n4/2023-05-maia/blob/main/src/hermes/tokens/bHermesVotes.sol#L36

## Tools Used
VScode 

## Recommended Mitigation Steps
Burning or minting of Hermes' governance token should be based on liquidity mechanism and not under control of owner.
When a user provides liquidity to project, governance token should then be minted and when removed from project the token will be burned.



## Assessed type

Other
Lack of valid Slippage control parameter in `increaseLiquidity` calls in Talos
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#L144-L145


# Vulnerability details

## Impact

Loss of funds due to Allowing Maximum Slippage.

## Proof of Concept

There are many instances throughout the codebase where slippage protection has not been used and `0` has been passed to slippage control instead.

Eg: `deposit` method in `TalosBaseStrategy`:

```solidity
File: TalosBaseStrategy.sol

  (liquidityDifference, amount0, amount1) = nonfungiblePositionManager.increaseLiquidity(
        INonfungiblePositionManager.IncreaseLiquidityParams({
            tokenId: _tokenId,
            amount0Desired: amount0Desired,
            amount1Desired: amount1Desired,
@->         amount0Min: 0,      // @audit-issue No Slippage Protection
@->         amount1Min: 0,
            deadline: block.timestamp        // @audit-issue Miner controlled Deadline
        })
    );

```
[Link to code](https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L144-L145)

In Uniswap's example docs [here](https://docs.uniswap.org/contracts/v3/guides/providing-liquidity/increase-liquidity), it is clearly stated that:

>We cannot change the boundaries of a given liquidity position using the Uniswap v3 protocol; increaseLiquidity can only increase the liquidity of a position.

>In production, amount0Min and amount1Min should be adjusted to create slippage protections.

It is worth noting the second point that `amount0Min` and `amount1Min` acts as a slippage protection and it should be adjusted in the production in order to protect the users from High Slippage.

But in the following instance, this slippage parameter is set to zero which is exposing the transaction to maximum slippage:

* [TalosStrategyVanilla.sol](https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/TalosStrategyVanilla.sol#L146-L147)
* [TalosBaseStrategy.sol 1](https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L144-L145)
* [TalosBaseStrategy.sol 2](https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L206-L207)
* [TalosBaseStrategy.sol 3](https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L357-L358)
* [PoolActions.sol](https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolActions.sol#L82-L83)

## Tools Used

VS Code

## Recommended Mitigation Steps

Allow users to pass the value of `amountXMin` as parameter.


## Assessed type

Uniswap
depositToPort is supposed to be marked payable and it is not 
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/ulysses-omnichain/ArbitrumBranchPort.sol#L45-L50


# Vulnerability details

## Impact
Since depositToPort() function is not marked payable, it might not be able to do what it is intended for.

## Proof of Concept
    function depositToPort(address _depositor, address _recipient, address _underlyingAddress, uint256 _deposit)
        external
        requiresBridgeAgent
    {
        address globalToken = IRootPort(rootPortAddress).getLocalTokenFromUnder(_underlyingAddress, localChainId);
        if (globalToken == address(0)) revert UnknownUnderlyingToken();

## Tools Used
Manual review 
## Recommended Mitigation Steps

Add the payable keyword
function depositToPort(address _depositor, address _recipient, address _underlyingAddress, uint256 _deposit)
        external payable
        requiresBridgeAgent
    {
        address globalToken = IRootPort(rootPortAddress).getLocalTokenFromUnder(_underlyingAddress, 


## Assessed type

Payable
bHermes mint quantity can be attacked by grief
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/hermes/bHermes.sol#L115-L117


# Vulnerability details

## Impact

bHermes's totalAssets taken from the asset balance, which can be manipulated, so exchangeRate can be manipulated to decreases the victim's balance(share).   
As long as the asset is directly transferred to bHermes' contract, the attack can be carried out. The earlier the asset quantity is low, so the more significant the attack effect will be. The maximum balance can be reduced to 1(not 0).  
However, since bHermes cannot withdraw the asset, it is a grief attack. 

## Proof of Concept

```solidity
    function totalAssets() public view virtual override returns (uint256) {
        return address(asset).balanceOf(address(this));
    }

    function convertToShares(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDiv(supply, totalAssets());
    }

    function previewDeposit(uint256 assets) public view virtual returns (uint256) {
        return convertToShares(assets);
    }
```

It is easy to see that the greater the totalAsset imbalance, the lesser the user's mint share

## Tools Used

Manual review

## Recommended Mitigation Steps

Use internal accounting instead of reading balanceOf


## Assessed type

ERC4626
exactSqrtPriceImpact is unnecessarily divided by 2, which restricts the range of price impact percentage
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#L250-L253


# Vulnerability details

## Impact

In times of high market turbulence where price impact needs to be set above 50% in order to swap, the position would not be able to properly rebalance.

## Proof of Concept

When rebalancing in TALOS, the protocol will eventually call UniswapV3Pool.swap.

```
https://github.com/Uniswap/v3-core/blob/main/contracts/UniswapV3Pool.sol#L595-L602
    /// @inheritdoc IUniswapV3PoolActions
    function swap(
        address recipient,
        bool zeroForOne,
        int256 amountSpecified,
>       uint160 sqrtPriceLimitX96,
        bytes calldata data
    ) external override noDelegateCall returns (int256 amount0, int256 amount1) {
```

Before calling swap, TALOS Poolvariables.sol will calculate the appropriate sqrtPriceLimitX96.

```
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolVariables.sol#L250-L253
        // Calculate Price limit depending on price impact
        uint160 exactSqrtPriceImpact = (sqrtPriceX96 * (_strategy.priceImpactPercentage() / 2)) / GLOBAL_DIVISIONER;
        sqrtPriceLimitX96 = zeroForOne ? sqrtPriceX96 - exactSqrtPriceImpact : sqrtPriceX96 + exactSqrtPriceImpact;
    }
```

Focusing on the `exactSqrtPriceImpact` calculation, we see that the `_strategy.priceImpactPercentage` is divided by 2. Price impact percentage is set by the owner in [TalosOptimizer.sol](https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/talos/TalosOptimizer.sol#L85-L90)

```
    function setPriceImpact(uint24 _priceImpactPercentage) external onlyOwner {
        if (_priceImpactPercentage >= 1e6 || _priceImpactPercentage == 0) {
            revert PriceImpactPercentageInvalid();
        }
        priceImpactPercentage = _priceImpactPercentage;
    }
```

The price impact percentage cannot be set above 1e6 (which is 100%) and 0. Back to the `exactSqrtPriceImpact` calculation, because price impact percentage is divided by 2, price impact cannot be set above 50% when the original range is from 0-100%. This division effective restricts the range that the price impact percentage can go, which restricts the flexibility of `sqrtPriceLimitX96` when swapping.  

## Tools Used

VSCode

## Recommended Mitigation Steps

Recommend removing the division by 2 beside the `priceImpactPercentage` variable.

```
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolVariables.sol#L250-L253
        // Calculate Price limit depending on price impact
-        uint160 exactSqrtPriceImpact = (sqrtPriceX96 * (_strategy.priceImpactPercentage() / 2)) / GLOBAL_DIVISIONER;
+        uint160 exactSqrtPriceImpact = (sqrtPriceX96 * (_strategy.priceImpactPercentage())) / GLOBAL_DIVISIONER;
        sqrtPriceLimitX96 = zeroForOne ? sqrtPriceX96 - exactSqrtPriceImpact : sqrtPriceX96 + exactSqrtPriceImpact;
    }
```


## Assessed type

Context
Division before multiplication could incur precision loss.
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/gauges/BaseV2Gauge.sol#L68


# Vulnerability details

## Impact
Division before multiplication could incur precision loss.



## Proof of Concept
Division before multiplication could incur precision loss.
```
constructor(FlywheelGaugeRewards _flywheelGaugeRewards, address _strategy, address _owner) {
        _initializeOwner(_owner);
        flywheelGaugeRewards = _flywheelGaugeRewards;
        rewardToken = _flywheelGaugeRewards.rewardToken();
        hermesGaugeBoost = BaseV2GaugeFactory(msg.sender).bHermesBoostToken();
        strategy = _strategy;

        epoch = (block.timestamp / WEEK) * WEEK; //@audit division before mul

        multiRewardsDepot = new MultiRewardsDepot(address(this));
    }
```

## Tools Used
Manual review

## Recommended Mitigation Steps
Always implement all divisions last whenever there is mathmatical operations involving multiplication and division in order not to incur precision loss.


## Assessed type

Math
`_checkpoints` may be inaccurate voting power on arbitrum
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/main/src/erc-20/interfaces/IERC20MultiVotes.sol#L19-L22


# Vulnerability details

## Impact

According to Arbitrum [Docs](https://developer.offchainlabs.com/time) block.number returns the most recently synced L1 block number. Once per minute the block number in the Sequencer is synced to the actual L1 block number. Thus, using `block.number` on arbitrum may lead to a wrong voting power being returned.

## Proof of Concept

```solidity
    
    /**
     * @notice A checkpoint for marking the number of votes from a given block.
     * @param fromBlock the block number that the votes were delegated.
     * @param votes the number of votes delegated.
     */
    struct Checkpoint {
        uint32 fromBlock;
        uint224 votes;
    }
    
    mapping(address => Checkpoint[]) private _checkpoints;
```

The purpose of using `Checkpoint` is to keep track of historical changes in voting weights for each address. The contract maintains a list of checkpoints for each address in the `_checkpoints` mapping. Each time there is a change in voting weight, a new checkpoint is created and added to the list for that address.

By storing these checkpoints, the contract can determine the current voting weight of an address at any given block number or calculate the voting weight at a specific block number in the past.

A simple poc to demonstrat ethe issue:

| Wall Clock time                   | 12:00 am | 12:00:15 am | 12:00:15 am | 12:00:45 am | 12:01 am | 12:01:15 am |
|-----------------------------------|----------|-------------|-------------|-------------|----------|-------------|
| L1 `block.number`                 | 1000     | 1001        | 1002        | 1003        | 1004     | 1005        |
| L2 `block.number`                 | 1000     | 1000        | 1000        | 1000        | 1004     | 1004        |
| Arbitrum Block number (from RPCs) | 370000   | 370005	     | 370006      | 370008      | 370012   | 370015      |

- At 12:00 am, Bob took some action that increased his voting power by 100.
- At 12:00:45 am, Bob took another action that decreased his voting power by 75.
- Although Bob made these changes at different times, `_checkpoints` mapping will store that both checkpoints were created at block 1000.

#### Bob:

- `Checkpoint 1: fromBlock = 1000, votes = 100`
- `Checkpoint 2: fromBlock = 1000, votes = 25`

## Tools Used

Manual Review

## Recommended Mitigation Steps

We recommend using `block.timestamp` rather than `block.number` when deploying on arbitrum.



## Assessed type

Timing
Interactions with AMMs do not use deadlines for operations
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#L147
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L208
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L269
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L359
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/TalosStrategyVanilla.sol#L148
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolActions.sol#L85


# Vulnerability details

## Impact
block.timestamp should not be used as a deadline. Doing so is essentially the same as not having a deadline at all. Transactions may become stuck in the mempool for an extended period, resulting in trades being executed way later than the user wants at unfavorable prices and potentially resulting in financial losses.

Related report : https://github.com/code-423n4/2022-11-paraspace-findings/issues/429

## Proof of Concept
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L147
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L208
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L269
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/base/TalosBaseStrategy.sol#L359
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/TalosStrategyVanilla.sol#L148
https://github.com/code-423n4/2023-05-maia/blob/main/src/talos/libraries/PoolActions.sol#L85

## Tools Used
Manual review

## Recommended Mitigation Steps
Add a valid deadline





## Assessed type

Uniswap
FlywheelCore.setBooster() can be used to steal unclaimed rewards
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/rewards/base/FlywheelCore.sol#L196-L204


# Vulnerability details

## Impact
A malicious authorized user can steal all unclaimed rewards and break the reward accounting

Even if the authorized user is benevolent the fact that there is a rug vector available may
 [negatively impact the protocol's reputation](https://twitter.com/RugDocIO/status/14117321080291819600). 
Furthermore since this contract is meant to be used by other projects, the trustworthiness of every project cannot be vouched for.


## Proof of Concept

By setting a booster that returns zero for all calls to boostedBalanceOf() where the user address is not under the attacker's control, and returning arbitrary values for those under his/her control, an attacker can choose specific amounts of rewardToken to assign to himself/herself. The attacker can then call claimRewards() to withdraw the funds. Any amounts that the attacker assigns to himself/herself over the amount that normally would have been assigned, upon claiming, is taken from other users' unclaimed balances, since tokens are custodied by the flywheelRewards address rather than per-user accounts.

https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/rewards/base/FlywheelCore.sol#L136-L141

https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/rewards/base/FlywheelCore.sol#L196-L204

https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/rewards/base/FlywheelCore.sol#L94-L100

Projects also using BaseFlywheelRewards or its child contrats, are implicitly approving infinite transfers by the core

https://github.com/code-423n4/2023-05-maia/blob/cfed0dfa3bebdac0993b1b42239b4944eb0b196c/src/rewards/base/BaseFlywheelRewards.sol#L31-L37

The attacker need not keep the booster set this way - he/she can set it, call accrue() for his/her specific user, and unset it, all in the same block

## Tools Used
Code inspection

## Recommended Mitigation Steps

Make flywheelRewards immutable, or only allow it to change if there are no current users



## Assessed type

Other
Incorrect refund of execution gas fee to user
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/main/src/ulysses-omnichain/RootBridgeAgent.sol#L867
https://github.com/code-423n4/2023-05-maia/blob/main/src/ulysses-omnichain/RootBridgeAgent.sol#L1184


# Vulnerability details

## Impact
The implementation of `anyExecute()`  and  `anyFallback` didn't take EIP-150 into consideration and user overpay for gas fee. The other problem is if a malicious executor can exploit it to drain out all execution fee, regardless of the actual execution cost. 

## Proof of Concept

When we calculate `_initialGas` only `63/64` is set and the remaining `1/64` gas is reserved to the caller contract which will be refunded to `executor` after the execution of the whole transaction. But calculation of `_initialGas`  includes this portion of the cost as well.

```solidity
860: function anyExecute(bytes calldata data)
        external
        virtual
        requiresExecutor
        returns (bool success, bytes memory result)
    {
        //Get Initial Gas Checkpoint
        uint256 _initialGas = gasleft();
    ................................................

1117: function anyFallback(bytes calldata data)
        external
        virtual
        requiresExecutor
        returns (bool success, bytes memory result)
    {
        //Get Initial Gas Checkpoint
        uint256 _initialGas = gasleft();
```
The first problem is if malicious executor exploit this to drain the execution fees.
The other is the users getting less than what they should be refunded because of EIP-150  `63/64` rule.

[EIP-150](https://eips.ethereum.org/EIPS/eip-150) defines the "all but one 64th" rule, which states that always at least 1/64 of the gas still not used for this transaction cannot be sent along. Therefore, in `_initialGas` is overstated by 1/64 and no refund back to users.

## Tools Used

Visual Studio Code

## Recommended Mitigation Steps

To fix this problem you can calculate the `_initialGas` like this:

```solidity
_initialGas -= gasleft() / 63;
```


## Assessed type

Other
castVoteBySig can be front run without proper access control
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/governance/GovernorBravoDelegateMaia.sol#L344
https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/governance/GovernorBravoDelegateMaia.sol#L349


# Vulnerability details

## Impact
`GovernorBravoDelegateMaia.sol`'s `castVoteBySig` does not have proper access control. Therefore, anyone can front-run the transaction and cast a vote. This can create unnecessary confusion among the DAO community.

## Proof of Concept
1. Alice is an Admin of the DAO.
2. Alice submitted the vote by `castVoteBySig` function.
3. Bob found this in mempool and front-run it.
4. Bob's transaction was executed first.
5. Alice's transaction will be failed and due to `castVoteInternal` validation.
6. Alice lost the gas fee too.
7. DAO community people could not understand why Alice's vote was cast by BOB.

https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/governance/GovernorBravoDelegateMaia.sol#L344

https://github.com/code-423n4/2023-05-maia/blob/54a45beb1428d85999da3f721f923cbf36ee3d35/src/governance/GovernorBravoDelegateMaia.sol#L349

## Tools Used
Manual Review

## Recommended Mitigation Steps

under the `castVoteBySig` function add this check `require(signatory != msg.sender, "GovernorBravo::castVoteBySig: invalid signatory");`



## Assessed type

Access Control
ONLY THE `owner` OF THE `tokenId` WILL BE ABLE TO RESTAKE THE LIQUIDITY NFT, EVEN AFTER THE INCENTIVE END TIME HAS PASSED 
Audit: 2023-05-maia-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-05-maia/blob/main/src/uni-v3-staker/UniswapV3Staker.sol#L342
https://github.com/code-423n4/2023-05-maia/blob/main/src/uni-v3-staker/UniswapV3Staker.sol#L373-L374


# Vulnerability details

## Impact
The `UniswapV3Staker.restakeToken()` function is used to `restake` the liquidity NFT every week by the users since the `Incentives` are weekly. The `restakeToken` function checks whether the `tokenId` is already staked, if so it will `unstake` first and then will retrieve the latest position info of the `tokenId` and will restake again.

The `unstake` of the `tokenId` happens as follows:

        if (incentiveId.startTime != 0) _unstakeToken(incentiveId, tokenId, true);

Once the `_unstakeToken()` function is called, if the `msg.sender == owner` then it will allow the unstaking of the `tokenId` given subsequent conditions are also satisfied. But as per the `Natspec` comments of the function, if the block time has passed the incentive end time (`block.timestamp >= endtime`) anyone (not necessarily the owner) can call the `restake` function. 

        // anyone can call restakeToken if the block time is after the end time of the incentive

But this is not true. Since inside the `UniswapV3Staker.restakeToken()` function, when calling the `_unstakeToken` function the `isNotRestake` is set to `true`. Which means irrespective of the `block.timestamp` is less or more than the `endtime` the following condition will result in `true` since it is `logical or` operation. 

    if (isNotRestake || block.timestamp < endTime)

As a result even after the incentive end time has passed only the `owner` of the `tokenId` will be able to call the `UniswapV3Staker.restakeToken()` function, contrary to what the protocol needs to achieve as mentioned in its comments. 

As a result if the owner forgets to `restake` his NFT after one week he will miss out on staking rewards since nobody else can restake on his behalf.

## Proof of Concept

```solidity
        if (incentiveId.startTime != 0) _unstakeToken(incentiveId, tokenId, true);
```

https://github.com/code-423n4/2023-05-maia/blob/main/src/uni-v3-staker/UniswapV3Staker.sol#L342

```solidity
        // anyone can call restakeToken if the block time is after the end time of the incentive
        if ((isNotRestake || block.timestamp < endTime) && owner != msg.sender) revert NotCalledByOwner();
```

https://github.com/code-423n4/2023-05-maia/blob/main/src/uni-v3-staker/UniswapV3Staker.sol#L373-L374

## Tools Used
Manual Review and VSCode

## Recommended Mitigation Steps

In order to achieve the intended behaviour of the protocol as far as restaking is concerned, it recommended to make the following change in the `restake()` function as shown below:

        if (incentiveId.startTime != 0) _unstakeToken(incentiveId, tokenId, false);

Here the `isNotRestake` is set to `false`. Now the restaking can be controlled by the `block.timestamp` and incentive `endTime` when `msg.sender