xanoutas/solidity-security-findings huggingface dataset:
Unrestricted Shares Transferability 
Audit: 2024-04-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/CollateralTracker.sol#L319-L353


# Vulnerability details

## Impact

The contract does not seem to limit shares transferrability. The lack of restrictions makes it possible for users to reduce their collateral by sending shares to other addresses. This may lead to situations when some positions are under-collateralized which can pose a liquidity risk to the protocol.  

## Proof of Concept

https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/CollateralTracker.sol#L319-L353

```solidity
function transfer(
    address recipient,
    uint256 amount
) public override(ERC20Minimal) returns (bool) {
    // make sure the caller does not have any open option positions
    if (s_panopticPool.numberOfPositions(msg.sender) != 0) revert Errors.PositionCountNotZero();
    return ERC20Minimal.transfer(recipient, amount);
}
function transferFrom(
    address from,
    address to,
    uint256 amount
) public override(ERC20Minimal) returns (bool) {
    // make sure the caller does not have any open option positions
    if (s_panopticPool.numberOfPositions(from) != 0) revert Errors.PositionCountNotZero();
    return ERC20Minimal.transferFrom(from, to, amount);
}
```

The transfer function checks if the senders have open positions in the protocol. However, if the sender has closed their positions before executing the transfers, they can still drain their balance.

## Tools Used

Manual review

## Recommended Mitigation Steps

To properly manage the risk of under-collateralization, it would be advisable to have stricter rules or restrictions around the transfer of shares. This might include implementing checks to prevent the transfer of shares from reducing a user's collateral below the required minimum for their open positions.


## Assessed type

Invalid Validation
Potential lose in precision due to the integer constraints
Audit: 2024-04-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticPool.sol#L1032
https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticPool.sol#L1598
https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticPool.sol#L1202


# Vulnerability details

## Impact
according to uniswap deocs - Using sqrtPriceX96 should be preferred over calculating the price from the current tick, because the current tick may lose precision due to the integer constraints

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

## Tools Used
Manual Review

## Recommended Mitigation Steps

The protocol should use sqrtPriceX96 in place of current tick


## Assessed type

Uniswap
`PanopticPool` can be initialized with wrong data
Audit: 2024-04-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticPool.sol#L291


# Vulnerability details

Users can initialize `PanopticPool` with incorrect data.
If user initializes `PanopticPool` using `PanopticFactory` no troubles would occur, however, if user wants to use PanopticPool separately, he/she can call `PanopticPool.startPool()` with any data that they want resulting to params _univ3pool, token0, token1, collateralTracker0, collateralTracker1 being not related at all. If user then wants to call any major functions they would revert as pool was initialized wrongly.

## Impact

Wrongly initialized `PanopticPool` is invalid and can not be used as all main functions would revert.

## Recommended Mitigation Steps

Add additional checks to ensure that `PanopticPool` is initialized correctly.

```diff
@@ -301,6 +301,11 @@ contract PanopticPool is ERC1155Holder, Multicall {
         // Store the univ3Pool variable
         s_univ3pool = IUniswapV3Pool(_univ3pool);
 
+        require(token0 == _univ3pool.token0());
+        require(token1 == _univ3pool.token1());
+        require(token0 == collateralTracker0.asset());
+        require(token1 == collateralTracker1.asset());
+
         (, int24 currentTick, , , , , ) = IUniswapV3Pool(_univ3pool).slot0();
```



## Assessed type

Invalid Validation
startToken is vulnerable to Frontrunning
Audit: 2024-04-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/CollateralTracker.sol#L221


# Vulnerability details

## Impact
The startToken function initializes critical aspects of the contract state, such as setting up whether token0 or token1 is considered the underlying token, setting up the Panoptic pool, the total supply of virtual shares, and various fees. If a malicious actor can see that a transaction is about to initialize these values, they could potentially front-run this transaction to set the initial state to their advantage or simply to prevent another user from successfully initializing the state (by causing the if (s_initialized) revert Errors.CollateralTokenAlreadyInitialized(); condition to trigger for the legitimate user).

Since startToken sets several economic parameters, a frontrunner could manipulate these initial conditions. This could include setting an advantageous fee structure or initializing the contract in a way that benefits them financially before any other users can interact under fair conditions.

Also if a malicious user front-runs a legitimate initialization, they could destabilize the intended operational logic of the contract. By causing the initialization to occur under their control, subsequent legitimate attempts to initialize would fail, leading to potential disruptions in how the contract was supposed to function, or in some cases, locking out legitimate administrative actions which rely on initial setup conditions.

## Proof of Concept
### Loc
https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/CollateralTracker.sol#L221

```solidity
function startToken(
        bool underlyingIsToken0,
        address token0,
        address token1,
        uint24 fee,
        PanopticPool panopticPool
    ) external {
        // fails if already initialized
        if (s_initialized) revert Errors.CollateralTokenAlreadyInitialized();
        s_initialized = true;

        // these virtual shares function as a multiplier for the capital requirement to manipulate the pool price
        // e.g if the virtual shares are 10**6, then the capital requirement to manipulate the price to 10**12 is 10**18
        totalSupply = 10 ** 6;

        // set total assets to 1
        // the initial share price is defined by 1/virtualShares
        s_poolAssets = 1;

        // store the address of the underlying ERC20 token
        s_underlyingToken = underlyingIsToken0 ? token0 : token1;

        // store the Panoptic pool for this collateral token
        s_panopticPool = panopticPool;

        // cache the pool fee in basis points
        uint24 _poolFee;
        unchecked {
            _poolFee = fee / 100;
        }
        s_poolFee = _poolFee;

        // Stores the addresses of the underlying tracked tokens.
        s_univ3token0 = token0;
        s_univ3token1 = token1;

        // store whether the current collateral token is token0 (true) or token1 (false; since there's always exactly tw
“sandwiching” front running 
Audit: 2024-04-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/SemiFungiblePositionManager.sol#L1185


# Vulnerability details

## Impact
The amount of tokens received from UniswapV3Pool functions might be manipulated by front-runners due to the decentralized nature of AMMs, where the order of transactions can not be pre-determined. A potential “sandwicher” may insert a buying order before the  call 
## Proof of Concept
    function _mintLiquidity(
        LiquidityChunk liquidityChunk,
        IUniswapV3Pool univ3pool
    ) internal returns (LeftRightSigned movedAmounts) {
        // build callback data
        bytes memory mintdata = abi.encode(
            CallbackLib.CallbackData({ // compute by reading values from univ3pool every time
                    poolFeatures: CallbackLib.PoolFeatures({
                        token0: univ3pool.token0(),
                        token1: univ3pool.token1(),
                        fee: univ3pool.fee()
                    }),
                    payer: msg.sender
                })
        );


        /// mint the required amount in the Uniswap pool
        /// @dev this triggers the uniswap mint callback function
        (uint256 amount0, uint256 amount1) = univ3pool.mint(
            address(this),
            liquidityChunk.tickLower(),
            liquidityChunk.tickUpper(),
            liquidityChunk.liquidity(),
            mintdata
        );


        // amount0 The amount of token0 that was paid to mint the given amount of liquidity
        // amount1 The amount of token1 that was paid to mint the given amount of liquidity
        // no need to safecast to int from uint here as the max position size is int128
        movedAmounts = LeftRightSigned.wrap(0).toRightSlot(int128(int256(amount0))).toLeftSlot(
            int128(int256(amount1))
        );
    }
## Tools Used

## Recommended Mitigation Steps

add extra priventive measure to secure this attack


## Assessed type

Context
Frontrunning Vulnerability in Multicall
Audit: 2024-04-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/multicall/Multicall.sol#L12


# Vulnerability details

## Impact
The `Multicall` smart contract exposes users to potential financial risks due to frontrunning vulnerabilities. As the contract batches multiple function calls into a single transaction, malicious actors can observe the transaction prior to its confirmation and execute their own transactions that capitalize on knowing the outcomes or intentions of the batched calls. This can be particularly detrimental in scenarios involving financial transactions, trading, or other critical operations that rely on the current state of the blockchain being unchanged. Users may experience financial losses, or their intended transactions may be preempted or rendered less effective.

## Proof of Concept
### Loc

https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/multicall/Multicall.sol#L12

```solidity
function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; ) {
            (bool success, bytes memory result) = address(this).delegatecall(data[i]);

            if (!success) {
                // Bubble up the revert reason
                // The bytes type is ABI encoded as a length-prefixed byte array
                // So we simply need to add 32 to the pointer to get the start of the data
                // And then revert with the size loaded from the first 32 bytes
                // Other solutions will do work to differentiate the revert reasons and provide paranthetical information
                // However, we have chosen to simply replicate the the normal behavior of the call
                // NOTE: memory-safe because it reads from memory already allocated by solidity (the bytes memory result)
                assembly ("memory-safe") {
                    revert(add(result, 32), mload(result))
                }
            }

            results[i] = result;

            unchecked {
                ++i;
            }
        }
    }
```


**Steps to Reproduce**:
1. Prepare a `multicall` transaction with multiple calls that will predictably alter contract state or market conditions.
2. Broadcast the transaction to the network.
3. An attacker observes the transaction in the mempool and crafts a transaction that would benefit from the anticipated state change.
4. The attacker submits their transaction with a higher gas fee to ensure it is mined first.

## Tools Used
Manual

## Recommended Mitigation Steps
Implement a commit-reveal scheme to obscure the intentions of transactions until after they are finalized.


## Assessed type

Other
Precision Loss in tickLower Calculation Leads to Incorrect Initialization of Liquidity Positions
Audit: 2024-04-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/PanopticFactory.sol#L392


# Vulnerability details

## Impact
An incorrect liquidity range can lead to higher slippage than expected for traders interacting with the pool, potentially resulting in less favorable prices 

Misaligned ticks could also create unintended arbitrage opportunities, potentially leading to exploitation where traders could benefit from discrepancies in expected versus actual liquidity ranges.

This line intends to calculate `tickLower` by aligning `Constants.MIN_V3POOL_TICK` to the nearest lower tick that is divisible by `tickSpacing`. In Solidity, integer division truncates any remainder, which means that when `Constants.MIN_V3POOL_TICK` is not an exact multiple of `tickSpacing`, the result of the division and subsequent multiplication results in a value that is less than `Constants.MIN_V3POOL_TICK`.

### Loc
https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/PanopticFactory.sol#L392

```solidity
tickLower = (Constants.MIN_V3POOL_TICK / tickSpacing) * tickSpacing;
```

## Proof of Concept
For example, if `Constants.MIN_V3POOL_TICK` is -887273 and `tickSpacing` is 10, the division of -887273 by 10 yields -88727 (truncated, discarding the remainder), and multiplying back by 10 gives -887270, which is 3 ticks higher than -887273.

This could result in setting the lower tick limit to a value slightly higher than intended, thereby not fully utilizing the possible range.

## Tools Used
Manual

## Recommended Mitigation Steps
Consider adjusting the calculation to ensure it rounds down to the nearest tick that's fully compliant with the tick spacing. If the intention is always to round down to the nearest valid tick, you could adjust the logic to account for negative numbers correctly. Here’s how you could modify the calculation:

```solidity
tickLower = (Constants.MIN_V3POOL_TICK / tickSpacing) * tickSpacing;
if (Constants.MIN_V3POOL_TICK % tickSpacing != 0) {
    tickLower -= tickSpacing;
}
```

This adjustment checks if there is a remainder in the division. If there is, it subtracts one `tickSpacing` from `tickLower`, ensuring that the result is always rounded down to the nearest valid tick, not rounded towards zero, which is the default behavior in Solidity for integer division.


## Assessed type

Math
Using slot0 for sqrtPriceX96 in order to calculate amount could lead to price manipulation
Audit: 2024-04-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticFactory.sol#L341


# Vulnerability details

The creation of a pool requires the creator to mint full-range liquidity into the corresponding Uniswap V3 pool. However, this fullRangeLiquidity is calculated using the slot0 SqrtPriceX96 from the Uniswap pool, which is susceptible to manipulation.

## Impact
MEV bots can utilize flash loans to front-run the creation of a pool, thereby increasing the costs for the user. The user may end up paying more token0 and token1 than necessary for creating the pool. Subsequently, these bots may execute trades that profit from the inflated prices after the pool's creation.

## Proof of Concept

## Tools Used
Manual Review
## Recommended Mitigation Steps
Implement the use of TWAP (Time-Weighted Average Price) instead.














## Assessed type

MEV
Overestimation of collateral requirements due to rounding errors in _computeSpread function
Audit: 2024-04-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/CollateralTracker.sol#L1570


# Vulnerability details

Accurate collateral calculations are crucial for maintaining the solvency of the Panoptic protocol. Underestimations can lead to insufficient collateral, risking the protocol's stability during market downturns, while overestimations can tie up unnecessary capital, reducing liquidity and trading efficiency.

The collateral requirement for spreads between two option legs is calculated as follows:


### Loc

https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/CollateralTracker.sol#L1570

```solidity
spreadRequirement = (notional < notionalP)
    ? Math.unsafeDivRoundingUp((notionalP - notional) * contracts, notional)
    : Math.unsafeDivRoundingUp((notional - notionalP) * contracts, notionalP);
```

This calculation can cause significant rounding errors due to integer division, particularly when the difference between `notional` and `notionalP` is minimal compared to their absolute values.

### audit details

> However, by far the most important functionality of the CollateralTracker is to calculate the collateral requirement for every account and position. Each time positions are minted or burned in Panoptic, the CollateralTracker updates the collateral balances and provides information on the collateral requirement, ensuring that the protocol remains solvent and we retain the ability to liquidate distressed positions when needed.

### Impact

The precision in collateral calculations impacts not just individual trades but the overall health and functionality of the trading platform which makes impact in this case significant.

1. Traders with limited capital may find themselves unable to participate in certain trades, or may incur higher opportunity costs as their funds are tied up unnecessarily.

2. Traders might perceive positions as riskier than they are, or the platform may inadvertently encourage over-collateralization, affecting the natural balance and hedging strategies in place. This could lead to misaligned risk perceptions and decisions.

3. Inaccuracies in collateral calculations might expose the platform to compliance risks if they're interpreted as failing to provide accurate accountings or as misleading users about the terms of engagement.

### Proof of Concept

Suppose we have:
- `notional` (amount moved in one leg of the spread): 1,000,000 tokens
- `notionalP` (amount moved in the other leg of the spread): 1,000,001 tokens
- `contracts` (size of the position): 10,000 contracts

This setup reflects a common scenario in financial derivatives where two legs are close in value but not identical, often seen in calendar spreads or tight vertical spreads.

**Calculation Without Scaling:**
Using the `_computeSpread` function, where `notional < notionalP`:
- Difference: `notionalP - notional = 1,000,001 - 1,000,000 = 1`
- Numerator before division: `1 * 10,000 = 10,000`

The division to be
Uniswap v3 callbacks access control should be hardened 
Audit: 2024-04-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/SemiFungiblePositionManager.sol#L435


# Vulnerability details

## Impact
Uniswap v3 uses a callback pattern to pull funds from the caller. The caller, (in this case Hypervisor) has to implement a callback function which will be called by the Uniswap’s pool. Both uniswapV3MintCallback and uniswapV3SwapCallback restrict the access to the callback functions only for the pool. However, this alone will not block a random call from the pool contract in case the latter was hacked, which will result in stealing all the funds held in Hypervisor or of any user that approved the Hypervisor contract to transfer tokens on his behalf.


## Proof of Concept
    /// @param data Contains the payer address and the pool features required to validate the callback
    function uniswapV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) external {
        // Decode the swap callback data, checks that the UniswapV3Pool has the correct address.
        CallbackLib.CallbackData memory decoded = abi.decode(data, (CallbackLib.CallbackData));
        // Validate caller to ensure we got called from the AMM pool
        CallbackLib.validateCallback(msg.sender, FACTORY, decoded.poolFeatures);


        // Extract the address of the token to be sent (amount0 -> token0, amount1 -> token1)
        address token = amount0Delta > 0
            ? address(decoded.poolFeatures.token0)
            : address(decoded.poolFeatures.token1);


        // Transform the amount to pay to uint256 (take positive one from amount0 and amount1)
        // the pool will always pass one delta with a positive sign and one with a negative sign or zero,
        // so this logic always picks the correct delta to pay
        uint256 amountToPay = amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);


        // Pay the required token from the payer to the caller of this contract
        SafeTransferLib.safeTransferFrom(token, decoded.payer, msg.sender, amountToPay);
    }


## Tools Used

## Recommended Mitigation Steps
Consider adding (boolean) storage variables that will help to track whether a call


## Assessed type

Uniswap