xanoutas/solidity-security-findings huggingface dataset:
Incorrect String Truncation in FactoryNFT Can Lead to Incomplete Panoptic Pool Addresses Within Metadata URI
Audit: 2024-06-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/base/FactoryNFT.sol#L79
https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/base/FactoryNFT.sol#L58-L112


# Vulnerability details

## Impact
The `toHexString` function from the `LibString` library is being used to convert the `panopticPool` address to a hexadecimal string representation. However, the second argument passed to `toHexString` is `20`, which specifies the desired length of the resulting string. [FactoryNFT contract (@contracts\base\FactoryNFT.sol:79)](https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/base/FactoryNFT.sol#L79)
```solidity
LibString.toHexString(uint256(uint160(panopticPool)), 20),
```
The problem is that an Ethereum address is 20 bytes long, which corresponds to 40 hexadecimal characters (each byte is represented by 2 hexadecimal digits). By passing 20 as the second argument, the function is requesting a string of only 20 characters, which is insufficient to represent the full address.

## Proof of Concept
A relevant code snippet that illustrates the issue: [FactoryNFT contract (@contracts\base\FactoryNFT.sol:58-112)](https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/base/FactoryNFT.sol#L58-L112)
```solidity
function constructMetadata(
    address panopticPool,
    string memory symbol0,
    string memory symbol1,
    uint256 fee
) public view returns (string memory) {
    // ...

    return
        string(
            abi.encodePacked(
                "data:application/json;base64,",
                Base64.encode(
                    bytes(
                        abi.encodePacked(
                            '{"name":"',
                            abi.encodePacked(
                                LibString.toHexString(uint256(uint160(panopticPool)), 20), // Incorrect length argument
                                "-",
                                // ...
                            ),
                            // ...
                        )
                    )
                )
            )
        );
}
```
As shown in the code, the `toHexString` function is called with `20` as the second argument, which is insufficient to represent the full Ethereum address.

Let's consider an example:

Suppose the `panopticPool` address is `0x1234567890123456789012345678901234567890`. When passed to the `toHexString` function with a length of 20, the resulting string will be truncated to `0x1234567890123456789`, which is only half of the actual address.

This truncated address will be included in the metadata URI, leading to the above mentioned issues. Any external systems or tools relying on the metadata may encounter difficulties in correctly identifying or interacting with the Panoptic Pool based on the incomplete address information.

## Tools U
Integer Overflow in Metadata Access Logic ([bytes32("descriptions")])
Audit: 2024-06-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/base/FactoryNFT.sol#L139-L147


# Vulnerability details

## Impact
[FactoryNFT contract (@contracts\base\FactoryNFT.sol:139-147)](https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/base/FactoryNFT.sol#L139-L147)
```solidity
svgOut = svgOut
    .replace(
        "<!-- TEXT -->",
        metadata[bytes32("descriptions")][lastCharVal + 16 * (rarity / 8)]
            .decompressedDataStr()
    )
    .replace("<!-- ART -->", metadata[bytes32("art")][lastCharVal].decompressedDataStr())
    .replace("<!-- FILTER -->", metadata[bytes32("filters")][rarity].decompressedDataStr());
```
The problem is with the index calculation `lastCharVal + 16 * (rarity / 8)` when accessing the `metadata[bytes32("descriptions")]` array.

If the value of `lastCharVal` is large enough, it could cause an integer overflow when added to `16 * (rarity / 8)`. This could lead to even out-of-bounds access to the metadata[bytes32("descriptions")] array.

## Proof of Concept
If the value of `lastCharVal` is large enough, the index calculation `lastCharVal + 16 * (rarity / 8)` can result in an integer overflow. This means that the calculated index could wrap around and become a smaller value than intended. As a result, the contract might access an element outside the valid range of the `metadata[bytes32("descriptions")]` array.

For example, let's say the `metadata[bytes32("descriptions")]` array has a length of 100. If `lastCharVal is 2^256 - 20` (a very large value) and `rarity` is 24, the calculated index would be.
```solidity
index = (2^256 - 20) + 16 * (24 / 8)
      = (2^256 - 20) + 48
      = 28 (due to integer overflow)
```
In this case, the contract would access `metadata[bytes32("descriptions")][28]`, which is within the array bounds but not the intended element.

To illustrate the concept further
```solidity
// Assume metadata[bytes32("descriptions")] has a length of 100
string[] memory descriptions = new string[](100);

// Set some example data
descriptions[0] = "Description 1";
descriptions[1] = "Description 2";
...
descriptions[99] = "Description 100";

// Assume lastCharVal is a very large value, e.g., 2^256 - 20
uint256 lastCharVal = type(uint256).max - 19;

// Assume rarity is 24
uint256 rarity = 24;

// Calculate the index
uint256 index = lastCharVal + 16 * (rarity / 8);

// Access the description using the calculated index
string memory description = descriptions[index];
```
In this example, `index` will be calculated as 28 due to integer overflow, and `description` will hold the value `"Description 29"` (assuming it exists), which is not the intended description for the given `lastCharVal` and rarity.

## Tools Used
Vs Code
FactoryNFT contract (@contracts\base\FactoryNFT.sol:58-112)
## Recommended Mitigation Steps
Ensure that the index calculation is performed safely and within the bounds of the
Integer Overflow in Pool ID Storage *unchecked Addition Can Lead to Incorrect Pool ID in SFPM
Audit: 2024-06-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/SemiFungiblePositionManager.sol#L385-L390


# Vulnerability details

## Impact
[SemiFungiblePositionManager Contract (@contracts/SemiFungiblePositionManager.sol:385-390)](https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/SemiFungiblePositionManager.sol#L385-L390)
```solidity
// store the UniswapV3Pool => poolId information in a mapping
// add a bit on the end to indicate that the pool is initialized
// (this is for the case that poolId == 0, so we can make a distinction between zero and uninitialized)
unchecked {
    s_AddrToPoolIdData[univ3pool] = uint256(poolId) + 2 ** 255;
}
```
The intention here is to store the `poolId` in the `s_AddrToPoolIdData` mapping and set the most significant bit to indicate that the pool is initialized. However, the addition of `2 ** 255` to the `poolId` can potentially cause an overflow.

If the `poolId` is already a large value close to the maximum value of `uint256`, adding `2 ** 255` to it will result in an overflow, and the stored value will be incorrect. This can lead to unexpected behavior and issues when retrieving the `poolId` from the mapping later on.

## Proof of Concept
The `initializeAMMPool` function stores the pool information in two mappings: `s_poolContext` and `s_AddrToPoolIdData`. If the `poolId` stored in `s_AddrToPoolIdData` is incorrect due to the overflow, there will be an inconsistency between the two mappings. This inconsistency can lead to further issues and unexpected behavior when accessing pool-related data.

For Example:
```solidity
// Assume the maximum value of uint256 is 2^256 - 1
uint256 maxUint256 = type(uint256).max;

// Assume the poolId is very close to the maximum value
uint64 poolId = uint64(maxUint256 - 10);

// Attempt to store the poolId with the most significant bit set
unchecked {
    s_AddrToPoolIdData[univ3pool] = uint256(poolId) + 2 ** 255;
}
```
The `poolId` is set to a value very close to the maximum value of uint256. When `2 ** 255` is added to it, an overflow occurs. The resulting value stored in `s_AddrToPoolIdData` will be incorrect and will not have the intended most significant bit set.

When this incorrect value is retrieved later from the mapping, it can lead to unexpected behavior and errors in other parts of the contract that rely on the `poolId`.

## Tools Used
Vs Code
## Recommended Mitigation Steps
Use bitwise OR (`|`) instead of addition.
```solidity
unchecked {
    s_AddrToPoolIdData[univ3pool] = uint256(poolId) | (1 << 255);
}
```
Using bitwise OR can set the most significant bit without the risk of overflow. The `1 << 255` expression shifts the bit 1 to the 255th position, effectively setting the most significant bit to 1 without affecting the other bits of the `poolId`.


## Assessed type

Math
UniswapV3 Callback Miscalculation in SFPM Risks Loss of Funds for Payers.
Audit: 2024-06-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/SemiFungiblePositionManager.sol#L452-L459


# Vulnerability details

## Impact
The logic for determining the `amountToPay`, the current implementation assumes that one of the deltas (`amount0Delta` or `amount1Delta`) will always be positive and the other will be negative or zero. However, this assumption may not always hold.

If both `amount0Delta` and `amount1Delta` are negative, the `amountToPay` will be incorrectly set to the absolute value of `amount1Delta`, even though no tokens need to be paid. This can lead to unintended token transfers and potential loss of funds for the payer.

Consider the following scenario:

   1. The Uniswap V3 pool executes a swap that results in both `amount0Delta` and `amount1Delta` being negative, indicating that the pool should receive tokens from the payer.
   2. The `uniswapV3SwapCallback` function is called with these negative deltas.
   3. The current implementation of the function incorrectly determines the `amountToPay` as the absolute value of `amount1Delta`.
   4. The function proceeds to transfer the `amountToPay` from the payer to the pool, even though no tokens should be transferred in this case.

As a result, the payer may lose funds unnecessarily, and the pool may receive tokens that it shouldn't have received.

[SemiFungiblePositionManager Contract (@contracts/SemiFungiblePositionManager.sol:452-459)](https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/SemiFungiblePositionManager.sol#L452-L459)
```solidity
// 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);
```
As mentioned earlier, the assumption that one of the deltas will always be positive and the other negative or zero is not always true. This can lead to the incorrect determination of `amountToPay` when both deltas are negative.

## Proof of Concept
Let's consider an example:

  1. The Uniswap V3 pool executes a swap that results in `amount0Delta = -100` and `amount1Delta = -50`, indicating that the pool should receive 100 tokens of token0 and 50 tokens of token1 from the payer.
  2. The `uniswapV3SwapCallback` function is called with these deltas.
  3. The current implementation incorrectly sets `amountToPay` to `uint256(amount1Delta)`, which is equivalent to `uint256(-50)`. Due to the unsigned integer conversion, `amountToPay` becomes a large positive value.
  4. The function proceeds to transfer this large amount of tokens from the payer to the pool,
Inaccurate Premium Accounting in SFPM Due to Incomplete Data Updates in registerTokenTransfer.
Audit: 2024-06-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/SemiFungiblePositionManager.sol#L642-L647


# Vulnerability details

## Impact
`registerTokenTransfer` does not update the `s_accountPremiumOwed` and `s_accountPremiumGross` mappings when transferring tokens.

When a token is transferred from one address to another, the function correctly updates the `s_accountLiquidity` and `s_accountFeesBase` mappings to reflect the transfer of liquidity and fees. However, it does not update the `s_accountPremiumOwed` and `s_accountPremiumGross` mappings, which store the premium owed and gross premium for each account.

This means that after a token transfer, the premium-related data will still be associated with the original owner's address instead of being transferred to the new owner. This can lead to incorrect accounting of premiums and potentially affect the calculation of fees and other related functionalities.

The lack of updating the `s_accountPremiumOwed` and `s_accountPremiumGross` mappings during token transfers in the `registerTokenTransfer` function can lead to several issues:
   1. After a token transfer, the premium-related data will still be associated with the original owner's address instead of being transferred to the new owner. This means that the new owner's premium owed and gross premium will not be accurately reflected in the contract's state.

   2. The premium data is used in various fee calculations throughout the contract. If the premium data is not properly transferred to the new owner, it can lead to incorrect fee calculations and distributions.

 1. The `registerTokenTransfer` function updates the `s_accountLiquidity` and `s_accountFeesBase` mappings during token transfers: [SemiFungiblePositionManager Contract (@contracts/SemiFungiblePositionManager.sol:642-647)](https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/SemiFungiblePositionManager.sol#L642-L647)
```solidity
// update+store liquidity and fee values between accounts
s_accountLiquidity[positionKey_to] = fromLiq;
s_accountLiquidity[positionKey_from] = LeftRightUnsigned.wrap(0);

s_accountFeesBase[positionKey_to] = fromBase;
s_accountFeesBase[positionKey_from] = LeftRightSigned.wrap(0);
```
However, it does not update the `s_accountPremiumOwed` and `s_accountPremiumGross` mappings.

 2. The `s_accountPremiumOwed` and `s_accountPremiumGross` mappings are defined in the contract.
```solidity
mapping(bytes32 => LeftRightSigned) internal s_accountPremiumOwed;
mapping(bytes32 => LeftRightUnsigned) internal s_accountPremiumGross;
```
 3. The premium data is used in various functions throughout the contract, such as `_getPremiaDeltas` and `_updateStoredPremia`:
```solidity
function _getPremiaDeltas(
    bytes32 positionKey,
    uint256 premium0X64,
    uint256 premium1X64
) internal view returns (uint256 premium0X64_delta, uint256 premium1X64_delta) {
    LeftRig
Users should not be allowed to mint more positions than the limit
Audit: 2024-06-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/CollateralTracker.sol#L459


# Vulnerability details

## Impact
The ability for users to mint more positions than a specified limit can lead to several issues within the system. If unchecked, this could:

* System Overload: Allowing an excessive number of positions can strain the system resources, leading to performance degradation or crashes.
* Economic Risks: It can lead to disproportionate allocation of rewards or risks, potentially destabilizing the economic model of the protocol.
* Security Vulnerabilities: Malicious actors could exploit this to create an excessive number of positions, thereby manipulating the protocol's behavior or creating unforeseen vulnerabilities.

## Proof of Concept
Documentation: `Users should not be allowed to mint more positions than the limit`
https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/CollateralTracker.sol#L459

## Tools Used

## Recommended Mitigation Steps
Implement Position Limit: Modify the `mint` function to include a check that prevents users from minting more positions than the predefined limit.


## Assessed type

Other
Array length should be checked in MetadataStore.sol.
Audit: 2024-06-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-panoptic/blob/main/contracts/base/MetadataStore.sol#L30


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
there is no check of array length in MetadataStore.sol.
## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
 constructor(
        bytes32[] memory properties,
        uint256[][] memory indices,
        Pointer[][] memory pointers
    ) {
        for (uint256 i = 0; i < properties.length; i++) {
            for (uint256 j = 0; j < indices[i].length; j++) {
        @>        metadata[properties[i]][indices[i][j]] = pointers[i][j];
            }
        }
    }
}
## Tools Used

## Recommended Mitigation Steps
require(properties.length()==indices.length());
require(MetadataStore.sol==pointers.length());


## Assessed type

Context
The value of `FORCE_EXERCISE_COST` may be too low and make forced exercises very cheap
Audit: 2024-06-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/CollateralTracker.sol#L747


# Vulnerability details

The README contains the following line :
```
For the purposes of this competition, assume the constructor arguments to the CollateralTracker are: 10, 2_000, 1_000, -128, 5_000, 9_000, 20_000
```
This means the intended value of `FORCE_EXERCISE_COST` is `-128` in basis points. The exercise cost is calculated as follows :

```solidity
            int256 fee = (FORCE_EXERCISE_COST >> (maxNumRangesFromStrike - 1)); // exponential decay of fee based on number of half ranges away from the price


            // store the exercise fees in the exerciseFees variable
            exerciseFees = exerciseFees
                .toRightSlot(int128((longAmounts.rightSlot() * fee) / DECIMALS_128))
                .toLeftSlot(int128((longAmounts.leftSlot() * fee) / DECIMALS_128));
```
A value of `-128` means that the highest possible exercise cost will be approximately 1% of `longAmounts` of user's positions, which makes forced exercises extremely cheap. The incorrectness of the mentioned value can also be verified through `PanopticPool.t.sol`, where the value is taken as `-1024` :
```solidity
collateralReference = address(
            new CollateralTracker(10, 2_000, 1_000, -1_024, 5_000, 9_000, 20_000)
        );
```
This value is more appropriate for pricing forced exercises.
 
## Impact
Cheaper forced exercises will destabilize the protocol and cause frequent movement in users' positions and liquidity across the protocol. This is harmful to the overall health of the protocol 
## Proof of Concept

## Tools Used
Manual Review
## Recommended Mitigation Steps
Change the value to `-1024`


## Assessed type

Other
After EIP-3074 owners would be unable to withdraw due to the `msg.sender != owner` check 
Audit: 2024-06-panoptic-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/CollateralTracker.sol#L513-L548


# Vulnerability details



## Proof of Concept

Take a look at https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/CollateralTracker.sol#L513-L548

```solidity
    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) external returns (uint256 shares) {
        if (assets > maxWithdraw(owner)) revert Errors.ExceedsMaximumRedemption();

        shares = previewWithdraw(assets);

        // check/update allowance for approved withdraw
        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        // burn collateral shares of the Panoptic Pool funds (this ERC20 token)
        _burn(owner, shares);

        // update tracked asset balance
        unchecked {
            s_poolAssets -= uint128(assets);
        }

        // transfer assets (underlying token funds) from the PanopticPool to the LP
        SafeTransferLib.safeTransferFrom(
            s_underlyingToken,
            address(s_panopticPool),
            receiver,
            assets
        );

        emit Withdraw(msg.sender, receiver, owner, assets, shares);

        return shares;
    }
```

This function is used to withdraw assests to the receiver by the owner, issue however is that the function includes a check that ` if (msg.sender != owner) ` which would cause for the attempt at withdrawing to fail after the implementation of EIP 3074 


Now would be key to note that `EIP-3074` has officially been included in the next Ethereum hard fork Pectra upgrade (Prague upgrade for short) ... [source](https://www.coinlive.com/news/eip-3074-is-included-in-the-ethereum-prague-upgrade-learn-eip3074), so we can conclude that the new [functionalities from the EIP proposal](https://eips.ethereum.org/EIPS/eip-3074) has been finalized and is to be adopted, so all current withdrawal attempts by integrators/users that actively decide use the new opcodes introduced with the EIP would not be able to have their withdrawals  executed.

## Impact

Availability of protocol's core functionality is affected, which would suffice as medium based on [Code4rena's severity categorization](https://docs.code4rena.com/awarding/judging-criteria/severity-categorization).

## Recommended Mitigation Steps

Consider reimplementing the check to ensure users making use of the EIP can still normally integrate with protocol.





## Assessed type

Context