xanoutas/solidity-security-findings huggingface dataset:
User can approve all tokens and not just that are required for transfer
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/tokens/ERC1155Minimal.sol#L77


# Vulnerability details



## Impact
```setApprovalForAll``` function allows a user to approve all token without checking whether they are listed on Uniswap or not. This can lead to loss of fund for user if a token is swapped for another token that is not listed on uniswap.

## Proof of Concept
As per the specification provided by the protocol 
```
- Transfers of ERC1155 SFPM tokens are very limited by design. It is expected that certain accounts will be unable to transfer or receive tokens.
Some tokens may not be transferable at all.

- Any compliant ERC20 token that is part of a Uniswap V3 pool and is not a fee-on-transfer token is supported, including ERC-777 tokens.
```
Only specific token will be used to carried out interaction but is ot followed in the ```setApprovalForAll``` function.

```setApprovalForAll``` function does not have any check for specific token and amount which can lead to unexpected behaviour like misuse of token or loss to the user.

```
 function setApprovalForAll(address operator, bool approved) public {
 isApprovedForAll[msg.sender][operator] = approved;

 emit ApprovalForAll(msg.sender, operator, approved);
 }

```

## Tools Used
Manual Review

## Recommended Mitigation Steps
The recommendation is made to approve only specific token and value to avoid any misue. 

```diff
-	function setApprovalForAll(address operator, bool approved) public {
+	function setApprovalForAll(address operator, bool approved, uint256 amount, address tokenAddress) public {
 
 // Use the ERC-20 approve function to allow spender to spend tokens on behalf of the caller
+	IERC20(tokenAddress).approve(operator, amount);
 isApprovedForAll[msg.sender][operator] = approved;

 emit ApprovalForAll(msg.sender, operator, approved);
 }
```



## Assessed type

Token-Transfer
False Overflow Reported by add(uint256,uint256) of LeftRight Library for values Within uint256 Maximum Limit
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/types/LeftRight.sol#L142-L153


# Vulnerability details

## Impact
This function is assumed to add two uint256s and return their result as uint256 but the flawed check causes the function to revert for values exceeding uint128 maximum. This can cause denial of services in Implementation contract when the expected values are more than uint128 maximum.

## Proof of Concept
Lets analyze the function to get clear picture

```solidity
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
    unchecked {
      z = x + y;
      if (z < x || (uint128(z) < uint128(x))) revert Errors.UnderOverFlow();
      }
  }
```
Initially, it performs the addition of x and y and stores the result in z. Then, it checks whether z is less than x in order to identify potential overflow. However, the issue arises with the logical OR condition, as the contract will report an overflow if any of the conditions are met.

**Picture this**
```
|| (uint128(z) < uint128(x))) revert Errors.UnderOverFlow();
```

what if we give the max uint128 value and add 33 to it would it report overflow?
if it does? does that mean that uint256 variable can't hold uint128 max + 33 ?

Assume, 
x = 33 ; 
y = 340282366920938463463374607431768211455 (uint128max)
therefore
**z = 340282366920938463463374607431768211488** [max128 +33]
    
**Now picture this check**
```
 if (z < x || (uint128(z) < uint128(x))) revert Errors.UnderOverFlow();

```
Is z less than x? No so the left check will be satisfied. But what about another check **(uint128(z) < uint128(x))**
    
here,
uint128(z) = uint128(340282366920938463463374607431768211488)
uint128(z) = 32
&
uint128(x) = 33

Now is (uint128(z) < uint128(x))) ?

Yes, therefore it will revert with  Errors.UnderOverFlow()

But in reality it shouldn't revert because uint256 can hold way larger data type.
Here the developer may have assumed uint128 for uint256, while in reality this function takes two uint256s and returns their addtion as uint256

Run this Unit Test anywhere inside 2023-11-panoptic/test/foundry/ with **forge test --match-test doodle -vvv** 

```solidity
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {LeftRight} from "@types/LeftRight.sol";


import "forge-std/Test.sol";

  contract LRTest is Test {
    using LeftRight for uint256;
    using LeftRight for uint128;

    uint128 max128U = type(uint128).max;
    uint256 max256U = type(uint256).max;


//  this will fail because of flawed check inside LeftRight library
    function test_AddUint256__fakeOverflow_doodle() public {
      uint256 a = 33;
      uint256 result = a.add(max128U);
      console.log(result);
    } 

    // this will pass because uint256 can easily handle this data
    function test_uint256_normal_shouldntFail_doodle() public {
      uint256 a = 33;
      uint256 result = a + max128U;
      console.log(result);
    }
    }
```

## Tools Used
Manual Analysi
Insufficient Input Validation in Swap Callback
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L441


# Vulnerability details

## Impact
Without proper input validation, the function could behave unexpectedly or be susceptible to manipulation.

The function assumes the amounts provided by the Uniswap pool are valid and does not perform any checks on these values


## 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

## Recommended Mitigation Steps

Add input validation to ensure the amounts are within expected ranges.

unction uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, ...) external {
require(amount0Delta >= 0 && amount1Delta >= 0, 'Invalid swap amounts');
// existing logic
}


## Assessed type

Invalid Validation
Unauthorized Swap Callback Execution	
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L441


# Vulnerability details

## Impact
If the callback is not properly authorized, it could be called by unauthorized actors, leading to unexpected behavior or loss of funds.

The function does not verify that it was called by the Uniswap pool associated with the current operation.	

## 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

## Recommended Mitigation Steps

Verify that the callback caller is the expected Uniswap pool.

function uniswapV3SwapCallback(...) external {
require(msg.sender == address(expectedPool), 'Caller must be Uniswap pool');
// existing logic
}


## Assessed type

Access Control
Both uniswapV3MintCallback() function are open to re-entrancy attacks leading to draining of funds due to callback
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L407
https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L441


# Vulnerability details


## Impact
Lack of re-entrancy check on ```uniswapV3SwapCallback``` functions have callbacks to ```msg.sender``` that can be used by the attacker to reenter the pool and drain the funds in the pool as it carried out interaction with tokens.

## Proof of Concept
```uniswapV3SwapCallback``` function have crucial importance as it carried out interaction in context of token transferring using ```safeTransferFrom``` which callbacks to ```msg.sender``` and create clear position for reentering the function.

```
 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, address(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)
 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
Manual Review

## Recommended Mitigation Steps

The recommendation is made to use OZ’ re-entrancy guard ```nonReentrant``` to avoid the potential threat.
 ```diff
 function uniswapV3SwapCallback(
 int256 amount0Delta,
 int256 amount1Delta,
 bytes calldata data
- ) external {
+ ) external nonReentrant {
 // 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, address(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)
 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);
 }
```



## Assessed type

Reentrancy
Casting integer types without checking for overflow
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L457
https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L1186
https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L1209


# Vulnerability details

## Impact
Many instances of both implicit and explicit casting between types exist, with both having the potential to impart overflow errors when casting between int and uint.

## Proof of Concept

Unsafe casting from int256 to uint256 existed and viceversa is carried out without any check for overflow.

```
File: SemiFungiblePositionManager.sol

Line: 457	 uint256 amountToPay = amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);

Line: 1186 movedAmounts = int256(0).toRightSlot(-int128(int256(amount0))).toLeftSlot(
 -int128(int256(amount1))

Line: 1209		 int256 amountToCollect = _getFeesBase(univ3pool, startingLiquidity, liquidityChunk).sub(

```

## Tools Used
Manual Review

## Recommended Mitigation Steps
The recommendation is made for using the OpenZeppelin’s SafeCast library to provide overflow checking when casting from one type of number to another. 



## Assessed type

Under/Overflow
Incorrect Slippage Handling
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L476


# Vulnerability details

## Impact
Incorrect handling of slippage limits could result in unintended trades or financial loss.
The function may not correctly enforce the provided slippage limits when performing swaps.

## 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

## Recommended Mitigation Steps

Ensure slippage limits are correctly enforced during token swaps.
Verify slippage limits before and after performing a swap


## Assessed type

Other
Unable to transfer tokens for some multiple legs `tokenId`s.
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L586-L591
https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L594-L602
https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L613-L630


# Vulnerability details

## Impact
Unable to transfer tokens for some multiple legs `tokenId`s as a result from the `positionKey` collision of legs.

## Proof of Concept
The transfer hook (`registerTokenTransfer`) will update user's position data after a token transfer. The value of `positionKey` is calculated from the properties of the `tokenId`. But not all properties of `tokenId` affect the value of `positionKey`, e.g. `isLong` does not affect the value of `positionKey`.
```solidity
594:            bytes32 positionKey_from = keccak256(
595:                abi.encodePacked(
596:                    address(univ3pool),
597:                    from,
598:                    id.tokenType(leg),
599:                    liquidityChunk.tickLower(),
600:                    liquidityChunk.tickUpper()
601:                )
602:            );
```
[L594-L602](https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L594-L602)

If a `tokenId` has multiple legs, and two of them have the same leg properties except for `isLong`. Then the liquidity chunk for the two legs will have the same value (calculated by `getLiquidityChunk`), resulting that the two legs have the same `positionKey`. For simplicity, we name the two legs as `leg-A` and `leg-B`.
```solidity
586:            uint256 liquidityChunk = PanopticMath.getLiquidityChunk(
587:                id,
588:                leg,
589:                uint128(amount),
590:                univ3pool.tickSpacing()
591:            );
```
[L586-L591](https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L586-L591)

Then account liquidity is updated for each leg (in `registerTokenTransfer`). Notice that the liquidity for the `leg-A` of `to` address is set a value after the update ([L626](https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L626)). When it comes to update the liquidity of `leg-B`, it will revert as its liquidity of `to` address is not 0 ([L615](https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L615)). This results from that `leg-B` has the same `positionKey` with `leg-A`, and that liquidity is mapped by `positionKey`.
```solidity
613:            // Revert if recipient already has that position
614:            if (
615:->              (s_accountLiquidity[positionKey_to] != 0) ||
616:                (s_accountFeesBase[positionKey_to] != 0)
617:            ) revert Errors.TransferFailed();
618:
619:            // Revert if not all balance is transferred
620:            uint256 fromLiq = s_ac
Insufficient Input Validation in Swap Callback
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/SemiFungiblePositionManager.sol#L441


# Vulnerability details

## Impact
Without proper input validation, the function could behave unexpectedly or be susceptible to manipulation.

The function assumes the amounts provided by the Uniswap pool are valid and does not perform any checks on these values.

## 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

## Recommended Mitigation Steps

Add input validation to ensure the amounts are within expected ranges.

function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, ...) external {
require(amount0Delta >= 0 && amount1Delta >= 0, 'Invalid swap amounts');
// existing logic
}


## Assessed type

Invalid Validation
Unauthorized Swap Callback Execution
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L441


# Vulnerability details

## Impact
If the callback is not properly authorized, it could be called by unauthorized actors, leading to unexpected behavior or loss of funds. 

The function does not verify that it was called by the Uniswap pool associated with the current operation.

## 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

## Recommended Mitigation Steps

Verify that the callback caller is the expected Uniswap pool. 
function uniswapV3SwapCallback(...) external {
require(msg.sender == address(expectedPool), 'Caller must be Uniswap pool');
// existing logic
}


## Assessed type

Access Control
Insufficient Input Validation in Mint Callback
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L407


# Vulnerability details

## Impact
Without proper input validation, the function could behave unexpectedly or be susceptible to manipulation.

## Proof of Concept
The function assumes the amounts provided by the Uniswap pool are valid and does not perform any checks on these values.

## Tools Used

## Recommended Mitigation Steps

Add input validation to ensure the amounts are within expected ranges.

function uniswapV3MintCallback(uint256 amount0Owed, uint256 amount1Owed, ...) external {
require(amount0Owed >= 0 && amount1Owed >= 0, 'Invalid mint amounts');
// existing logic
}


## Assessed type

Invalid Validation
Authorization: Unauthorized Mint Callback Execution
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L407


# Vulnerability details

## Impact
If the callback is not properly authorized, it could be called by unauthorized actors, leading to unexpected behavior or loss of funds.
The function does not verify that it was called by the Uniswap pool associated with the current operation.


## 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

## Recommended Mitigation Steps

Verify that the callback caller is the expected Uniswap pool.

unction uniswapV3MintCallback(...) external {
require(msg.sender == address(expectedPool), 'Caller must be Uniswap pool');
// existing logic
}



## Assessed type

Access Control
Insufficient Input Validation
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L351


# Vulnerability details

## Impact
Without proper validation, the function could be called with invalid parameters, leading to failed transactions or incorrect pool setup.
The function assumes that the Uniswap V3 pool address derived from the factory is valid without additional checks

## 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

## Recommended Mitigation Steps

Add input validation to ensure parameters are correct and the derived pool address is valid.

function initializeAMMPool(address token0, address token1, uint24 fee) external {
require(token0 != address(0) && token1 != address(0), 'Invalid token addresses');
require(fee > 0, 'Invalid fee');
// existing logic
}


## Assessed type

Invalid Validation
Lack of Access Control on Pool Initialization
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L351


# Vulnerability details

## Impact
Any user can initialize a pool, which could lead to unauthorized pool initialization and potential denial of service if not properly controlled

## Proof of Concept
The function does not restrict who can call `initializeAMMPool`, allowing anyone to potentially initialize a pool with incorrect parameters. 

## Tools Used

## Recommended Mitigation Steps
Implement access control to restrict who can initialize pools
modifier optionsManagers() {
// isOptionsManagers can be an address key in a map
require(msg.sender == isOptionsManagers(msg.sender), 'Not Options Manager');
_;
}
function initializeAMMPool(address token0, address token1, uint24 fee) external isOptionsManagers {
// existing logic
}


## Assessed type

Access Control
Reentrancy lock can be disabled for the first mint
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L521


# Vulnerability details

## Impact
The first mint can be reentered. In case the ERC777 transfer hook vulnerability is protected using a reentrancy lock, this will allow the attacker to perform the attack.
The team has used reentrancyLock for mints and burns and if there was some assumption it would break 

## Proof of Concept
In `mintTokenizedPosition` function the existance of the pool is only checked after minting the ERC1155 token
https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L521
```solidity
    function mintTokenizedPosition(
        uint256 tokenId,
        uint128 positionSize,
        int24 slippageTickLimitLow,
        int24 slippageTickLimitHigh
    )
        external
        ReentrancyLock(tokenId.univ3pool())
        returns (int256 totalCollected, int256 totalSwapped, int24 newTick)
    {
        
        _mint(msg.sender, tokenId, positionSize);

        emit TokenizedPositionMinted(msg.sender, tokenId, positionSize);

       // @audit existance of pool is checked inside this function
        (totalCollected, totalSwapped, newTick) = _validateAndForwardToAMM(
```
https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L683
```solidity
    function _validateAndForwardToAMM(
        uint256 tokenId,
        uint128 positionSize,
        int24 tickLimitLow,
        int24 tickLimitHigh,
        bool isBurn
    ) internal returns (int256 totalCollectedFromAMM, int256 totalMoved, int24 newTick) {
        
        ..........

        IUniswapV3Pool univ3pool = s_poolContext[tokenId.validate()].pool;


        // Revert if the pool not been previously initialized
        if (univ3pool == IUniswapV3Pool(address(0))) revert Errors.UniswapPoolNotInitialized();
```
This allows an attacker to call the `mintTokenizedPosition` function on an uninitialized pool and initialize it by reentering `SemiFungiblePositionManager` via the ERC1155 `onERC1155Received` call. Initializing a pool will set its reentrancy lock to false
https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol#L351-378
```solidity
    function initializeAMMPool(address token0, address token1, uint24 fee) external {

        ......        

        // @audit set reentrancy lock to false
        s_poolContext[poolId] = PoolAddressAndLock({
            pool: IUniswapV3Pool(univ3pool),
            locked: false
        });
```

## Tools Used
Manual review

## Recommended Mitigation Steps
Check whether the pool is initialized before minting the token


## Assessed type

Reentrancy