xanoutas/solidity-security-findings huggingface dataset:
Use of `slot0` to get `sqrtPriceLimitX96` can lead to price manipulation.
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Pool.sol#L317-L322
https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Pool.sol#L411-L441
https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Pool.sol#L470-L494


# Vulnerability details

Lines of code
https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Pool.sol#L317-L322
https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Pool.sol#L411-L441
https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Pool.sol#L470-L494

Vulnerability Details: The `IKatanaV3Pool` contract relies on the `slot0.sqrtPriceX96` (the current price) for calculating token0 and token1 amounts during liquidity **minting** and **burning** operations. However, `slot0.sqrtPriceX96` can be manipulated using flash loans or short-term price manipulation strategies. Since the **current price** is not validated against a longer-term price or an average price, the contract is vulnerable to attacks where the price is momentarily manipulated to benefit the attacker.

Impact:
By manipulating `slot0.sqrtPriceX96`, an attacker can:

- During minting, force the pool to calculate incorrect amounts of token0 and token1, leading to potentially unfavorable conditions for liquidity providers.
- During burning, manipulate the withdrawal amounts, allowing the attacker to gain more than intended by exploiting price manipulation.

The vulnerability exposes the contract to flash loan-based price manipulation attacks, leading to incorrect token amounts during minting or burning liquidity. This could result in financial loss to liquidity providers or protocol participants.

Proof of Concept:
1. Price Manipulation with Flash Loan:
  The attacker uses a flash loan to manipulate the price of the Uniswap pool, driving the price in `slot0.sqrtPriceX96` to an artificial value.
  They call the mint or burn function during this period where the manipulated price is reflected in `slot0.sqrtPriceX96`.
As a result, the amount0 and amount1 values are incorrectly calculated, benefiting the attacker.
2. In mint Function:
  The manipulated `sqrtPriceX96` is used to calculate the required amounts of token0 and token1 for adding liquidity using `SqrtPriceMath.getAmount0Delta` and `getAmount1Delta`.
The attacker mints liquidity at an unfair exchange rate due to the manipulated price.

3. In burn Function:
  The attacker withdraws liquidity while the manipulated price in `slot0.sqrtPriceX96` still holds, receiving incorrect amounts of token0 and token1.

Tools Used:
Manual code review.

Recommended Mitigation Steps:
1. Use TWAP (Time-Weighted Average Price):

Implement a time-weighted average p
Missing authorization check in `increaseLiquidity` permits unauthorized liquidity addition
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/periphery/NonfungiblePositionManager.sol#L246-L252


# Vulnerability details

## Proof of Concept

`NonfungiblePositionManager` misses the necessary authorization check, allowing any user to increase the liquidity of any position, regardless of ownership.

https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/periphery/NonfungiblePositionManager.sol#L246-L252

```solidity
function increaseLiquidity(IncreaseLiquidityParams calldata params)
  external
  payable
  override
  checkDeadline(params.deadline)
  returns (uint128 liquidity, uint256 amount0, uint256 amount1)
```

An attacker can orchestrate this issue using a contract similar to the following:

```solidity
pragma solidity ^0.8.20;

import "./NonfungiblePositionManager.sol";

contract UnauthorizedLiquidityAdder {
    NonfungiblePositionManager public nonfungiblePositionManager;

    constructor(address _nonfungiblePositionManager) {
        nonfungiblePositionManager = NonfungiblePositionManager(_nonfungiblePositionManager);
    }

    function addLiquidityToAnotherPosition(
        uint256 targetTokenId,
        uint256 amount0Desired,
        uint256 amount1Desired
    ) external payable {
        NonfungiblePositionManager.IncreaseLiquidityParams memory params = NonfungiblePositionManager
            .IncreaseLiquidityParams({
                tokenId: targetTokenId,
                amount0Desired: amount0Desired,
                amount1Desired: amount1Desired,
                amount0Min: 0,
                amount1Min: 0,
                deadline: block.timestamp + 1 days
            });

        // Unauthorized increase of liquidity on a tokenId not owned by this contract
        nonfungiblePositionManager.increaseLiquidity{value: msg.value}(params);
    }
}
```

This exploit allows an attacker to manipulate the liquidity of any position.

Consider a scenario:
- Alice: A legitimate user who owns a valuable position
- Eve: The attacker

Step 1: Initial Setup
1. Alice creates a position in the Uniswap V3 pool using the `NonfungiblePositionManager`.
2. Alice's position (let's say with `tokenId` 1234) has 10 ETH and 10,000 USDC, providing liquidity in the 1500-2000 USDC/ETH price range.

Step 2: 
1. Eve deploys the `UnauthorizedLiquidityAdder` contract, passing the address of the `NonfungiblePositionManager` in the constructor.

Step 3: 
1. Eve calls the `addLiquidityToAnotherPosition` function on her `UnauthorizedLiquidityAdder` contract with the following parameters:
   - `targetTokenId`: 1234 (Alice's position)
   - `amount0Desired`: 5 ETH
   - `amount1Desired`: 5,000 USDC
2. Eve includes 5 ETH in the transaction as `msg.value`.

Step 4: 
1. The `UnauthorizedLiquidityAdder` contract calls `increaseLiquidity` on the `NonfungiblePositionManager`.
2. Due to the missing authorization check, the transaction succeeds.
3. Alice's pos
Precision Loss in Oracle's Tick Cumulative Calculation Due to Integer Division Order 
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/libraries/Oracle.sol#L231


# Vulnerability details


## Issue Details
The Oracle's tick cumulative calculation suffers from significant precision loss due to performing division before multiplication in integer arithmetic operations. This implementation can lead to substantial undervaluation of tick cumulative values, potentially affecting pricing and fee calculations.

### Code part
https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/libraries/Oracle.sol#L231

```
  function observeSingle(
    Observation[65535] storage self,
    uint32 time,
    uint32 secondsAgo,
    int24 tick,
    uint16 index,
    uint128 liquidity,
    uint16 cardinality
  ) internal view returns (int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128) {
    if (secondsAgo == 0) {
      Observation memory last = self[index];
      if (last.blockTimestamp != time) last = transform(last, time, tick, liquidity);
      return (last.tickCumulative, last.secondsPerLiquidityCumulativeX128);
    }

    uint32 target = time - secondsAgo;

    (Observation memory beforeOrAt, Observation memory atOrAfter) =
      getSurroundingObservations(self, time, target, tick, index, liquidity, cardinality);

    if (target == beforeOrAt.blockTimestamp) {
      // we're at the left boundary
      return (beforeOrAt.tickCumulative, beforeOrAt.secondsPerLiquidityCumulativeX128);
    } else if (target == atOrAfter.blockTimestamp) {
      // we're at the right boundary
      return (atOrAfter.tickCumulative, atOrAfter.secondsPerLiquidityCumulativeX128);
    } else {
      // we're in the middle
      uint32 observationTimeDelta = atOrAfter.blockTimestamp - beforeOrAt.blockTimestamp;
      uint32 targetDelta = target - beforeOrAt.blockTimestamp;
      return (
        beforeOrAt.tickCumulative
          + ((atOrAfter.tickCumulative - beforeOrAt.tickCumulative) / observationTimeDelta) * targetDelta,
        beforeOrAt.secondsPerLiquidityCumulativeX128
          + uint160(
            (
              uint256(atOrAfter.secondsPerLiquidityCumulativeX128 - beforeOrAt.secondsPerLiquidityCumulativeX128)
                * targetDelta
            ) / observationTimeDelta
          )
      );
    }
  }

```
## Technical Analysis

**Current Implementation**
```solidity
tickCumulative = beforeOrAt.tickCumulative + 
    ((atOrAfter.tickCumulative - beforeOrAt.tickCumulative) / observationTimeDelta) * targetDelta
```

The current implementation divides first, which can result in the quotient being rounded down to zero, especially when the difference between tick cumulatives is smaller than the observation time delta.

### **Proof Of Concept**
```solidity

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

contract OracleTest {
    // Function to test precision loss
    function test_precisionLoss() public {

        uint bef
Unauthorized Liquidity Manipulation in NonfungiblePositionManager Contract Due to Missing Access Control
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

 https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/periphery/NonfungiblePositionManager.sol#L246


# Vulnerability details

### Vulnerability Overview

#### Vulnerability Details
**Impact of the Vulnerability**:  
The `increaseLiquidity` function within the `NonfungiblePositionManager` contract lacks adequate access control mechanisms. Specifically, it does not implement the `isAuthorizedForToken(params.tokenId)` modifier, allowing unauthorized users to manipulate liquidity for token positions they do not own.

### Part code

https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/periphery/NonfungiblePositionManager.sol#L246C1-L294C4

``` solidity
function increaseLiquidity(IncreaseLiquidityParams calldata params)
    external
    payable
    override
    checkDeadline(params.deadline)
    returns (uint128 liquidity, uint256 amount0, uint256 amount1)
  {
    Position storage position = _positions[params.tokenId];

    PoolAddress.PoolKey memory poolKey = _poolIdToPoolKey[position.poolId];

    IKatanaV3Pool pool;
    (liquidity, amount0, amount1, pool) = addLiquidity(
      AddLiquidityParams({
        token0: poolKey.token0,
        token1: poolKey.token1,
        fee: poolKey.fee,
        tickLower: position.tickLower,
        tickUpper: position.tickUpper,
        amount0Desired: params.amount0Desired,
        amount1Desired: params.amount1Desired,
        amount0Min: params.amount0Min,
        amount1Min: params.amount1Min,
        recipient: address(this)
      })
    );

    bytes32 positionKey = PositionKey.compute(address(this), position.tickLower, position.tickUpper);

    // this is now updated to the current transaction
    (, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128,,) = pool.positions(positionKey);

    position.tokensOwed0 += uint128(
      FullMath.mulDiv(
        feeGrowthInside0LastX128 - position.feeGrowthInside0LastX128, position.liquidity, FixedPoint128.Q128
      )
    );
    position.tokensOwed1 += uint128(
      FullMath.mulDiv(
        feeGrowthInside1LastX128 - position.feeGrowthInside1LastX128, position.liquidity, FixedPoint128.Q128
      )
    );

    position.feeGrowthInside0LastX128 = feeGrowthInside0LastX128;
    position.feeGrowthInside1LastX128 = feeGrowthInside1LastX128;
    position.liquidity += liquidity;

    emit IncreaseLiquidity(params.tokenId, liquidity, amount0, amount1);
  }

```

#### Proof of Concept
To demonstrate this vulnerability, an unauthorized user can exploit the lack of access control to increase the liquidity of a position. 

**Example Code**:

```solidity
pragma solidity ^0.8.20;

import "./NonfungiblePositionManager.sol";

contract UnauthorizedLiquidityAdder {
    NonfungiblePositionManager public nonfungiblePositionManager;

    constructor(address _nonfungiblePositionManager) {
        nonfungiblePositionManager = NonfungiblePositionManager(_nonfungibl
Katana Governance will never be able to initialize the V3factory because of a wrong check
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Factory.sol#L32-L35
https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Factory.sol#L46-L74


# Vulnerability details

## Proof of Concept

** Summary **
The Katana governance system cannot initialize the `v3Factory` due to an incorrect check within the `initialize` function. When the `v3Factory` is deployed, the constructor sets the `beacon` address to `address(1)`, disabling initialization by default. However, when the `initialize` function is called, it checks if `beacon` is `address(0)` instead of `address(1)`, causing the function to revert every time. This misconfiguration blocks the governance system from setting key parameters and using the `v3Factory`.

** Vulnerability Details **
In the current setup, when the `v3Factory` is deployed, the constructor includes this line:

```solidity
constructor() {
    // disable initialization
@audit >>1. >>     beacon = address(1);

}
```
This line sets the `beacon` address to `address(1)`, effectively disabling the initialization until it’s called with valid parameters. However, the `initialize` function attempts to validate the uninitialized state of the `beacon` by checking for `address(0)`, which will always fail and cause a reversion. This prevents any further setup for governance, as initialization cannot proceed.

** Code Reference **


1.  Constructor Setting the Beacon


```solidity
constructor() {
    // disable initialization

@audit >>1. >>      beacon = address(1);

}
```

2.  `initialize` Function with Incorrect Check


```solidity
function initialize(address beacon_, address owner_, address treasury_) external {
    
@audit >>REVERT >> require(beacon == address(0), "KatanaV3Factory: ALREADY_INITIALIZED");

    require(beacon_ != address(0), "KatanaV3Factory: INVALID_BEACON");
    require(owner_ != address(0), "KatanaV3Factory: INVALID_OWNER");
    require(treasury_ != address(0), "KatanaV3Factory: INVALID_TREASURY");
    // Additional setup logic follows...
}
```

** Impact **
This misconfiguration in the `initialize` function has significant implications:
1. **Governance Lockout**: The governance will not be able to initialize `v3Factory`, preventing essential operations, such as setting fees and controlling the factory.
2. **Operational Risk**: As governance cannot proceed with the `v3Factory` configuration, the system becomes incomplete and non-functional in its intended capacity.



## Recommended Mitigation Steps
To resolve this issue, update the check in the `initialize` function to confirm if `beacon` is set to `address(1)` instead of `address(0)`. This will align with the constructor configuration and allow the `initialize` function to proceed only when `beacon` is `address(1)`.

**Updated `initialize` Function Recommendation**:
```solidity
function initialize(address beacon_, address owne
Authorization Bypass Due to Expired Timestamp Check
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

https://github.com/ronin-chain/katana-operation-contracts/blob/27f9d28e00958bf3494fa405a8a5acdcd5ecdc5d/src/governance/KatanaGovernance.sol#L378


# Vulnerability details

The  `_isAuthorized` function allows access when block.timestamp is greater than the expiry timestamp, which is the opposite of the expected behavior. This logic flaw effectively allows accounts to maintain authorization even after the intended expiry period has passed, potentially bypassing security restrictions.
In the Dispatcher.sol contract, the checkAuthorizedV3Path function calls isAuthorized, which relies on the _isAuthorized function to verify permissions. Due to a logic flaw in _isAuthorized, accounts are incorrectly granted authorization after the expiry timestamp has passed. This unintended behavior could allow unauthorized access to critical functionality, leading to potential misuse or exploitation of restricted actions.
this vulnerability has high severity because it bypasses intended security restrictions.
Mitigation:

```javascript
if (expiry == AUTHORIZED || block.timestamp < expiry) return true;
```


## Assessed type

Access Control
KatanaGovernance::_isAuthorized function allows user to perform action even after expiry time has passed.
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

https://github.com/ronin-chain/katana-operation-contracts/blob/27f9d28e00958bf3494fa405a8a5acdcd5ecdc5d/src/governance/KatanaGovernance.sol#L375-L381


# Vulnerability details

## Proof of Concept

If current block time is greater than expiry time then **_isAuthorized** function returns true.
This logic allow users to perform action even after the expiry time has ended which could  allow users to perform unauthorized actions and make project unstable and.

## Recommended Mitigation Steps



```solidity 
/**
   * @dev Checks if an account is authorized.
   * @param account The address of the account to check authorization for.
   * @return A boolean indicating whether the account is authorized or not.
   */
  function _isAuthorized(Permission storage $, address account) private view returns (bool) {
    uint256 expiry = $.whitelistUntil;
    if (expiry == UNAUTHORIZED) return false;
    // if (expiry == AUTHORIZED || block.timestamp > expiry) return true;
    if (expiry == AUTHORIZED || block.timestamp < expiry) return true;

    return $.allowed[account];
  }

```








## Assessed type

Access Control
Wrong Implementation, `KatanaV3Factory` never be initialized.
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Factory.sol#L47


# Vulnerability details

# **Description** 
The `initialize` function only executed if beacon is zero else this revert an ALREADY_INITIALIZED error. But in `KatanaV3Factory` contract we initialize beacon as `beacon = address(1)`. The `initialize` function have `require(beacon == address(0), "KatanaV3Factory: ALREADY_INITIALIZED")` check which only allow to initialize if beacon is address zero but it already initialize in contructor as address(1). 

# **Impact** 
Contract's `initialize` function is throws error always or deadcode.

# **Proof of Concepts**

- This similar code outputs result as initialize function always thorws error: 

```// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

contract test_initialize{
    address public beacon;
    constructor() {
        beacon = address(1);
    }

    function initialize(address _beacon) public {
        require(beacon == address(0), "Already_Initialized");
        beacon = _beacon;
    }
}   
```

- Run this code, I got : 
```
transact to test_initialize.initialize errored: Error occurred: revert.

revert
	The transaction has been reverted to the initial state.
Reason provided by the contract: "Already_Initialized".
```

# **Recommended mitigation**

- Remove the check and apply suitable options.
- check whether initializing in constructor is required or not. 


## Assessed type

Other
Wrong and unexpected parameters passed to constructor in `KatanaV3PoolProxy`.
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3PoolProxy.sol#L11


# Vulnerability details

# **Description**
This `KatanaV3PoolProxy` contract have a `constructor` with parameter as `address(0)` passed to `beaconProxy` contract which further `_setBeacon` with zero address. This address(0) is passed as beacon address to `beaconProxy` and then `beaconProxy` contract's constructor call `_setBeacon` function with address(0) as beacon. This `_setBeacon` function has a check which revert this call `require(Address.isContract(beacon),"BeaconProxy: beacon is not a contract");`.

# **Impact** 
`KatanaV3PoolProxy` contract always revert on deployment, restricted code or dead contract. Because this can never be initialized.

# **Proof of Concepts**

- address(0) passed from `KatanaV3PoolProxy` contract:
 ``` constructor() BeaconProxy(address(0), "") { } ```

- `BeaconProxy`'s Contructor called _setBeacon:
 ``` javascript
 constructor(address beacon, bytes memory data) payable {
        assert(_BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1));
        _setBeacon(beacon, data);
    }
 ```
- `_setBeacon` requires checks:
``` javascript
function _setBeacon(address beacon, bytes memory data) internal virtual {
        require(
            Address.isContract(beacon),
            "BeaconProxy: beacon is not a contract"
        );
```

- So address(0) can't be a contract's address, It reverts.



## Assessed type

Other
V3factory will fail to initialize because of a wrong check
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Pool.sol#L122
https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Pool.sol#L112-L113


# Vulnerability details

## Proof of Concept

The `initialize` function in the v3Katanapool contract has a misconfiguration that causes it to revert unexpectedly, preventing initialization of the pool parameters. Here’s an analysis of the code and impact:

1. **Issue**: When the `initialize` function is called, it checks if `factory` is `address(0)` rather than `address(1)`. This check fails each time because the constructor sets `factory` to `address(1)`, causing the `initialize` function to revert and halt the pool setup.

2. **Code Reference**:

   - **Constructor**: 
    
 ```solidity
     constructor() {

         // Disable immutables initialization
@audit>>         factory = address(1);

     }
  ```
  
 - **Initialize Function**:
    
 ```solidity
     function initializeImmutables(address factory_, address token0_, address token1_, uint24 fee_, int24 tickSpacing_)
         public
         virtual
         override
     {

@audit>>          require(factory == address(0), "AII");
         // Other initialization code

     }
   ```

3. **Impact**: This bug blocks the contract from setting key parameters and utilizing `v3Pool`, effectively making the system unusable until corrected.


## Recommended Mitigation Steps

To fix this issue:

- **Solution**: Modify the `initialize` function's check to ensure `factory` is set to `address(1)` instead of `address(0)`.

- **Code Update**:
  ```solidity
  function initializeImmutables(address factory_, address token0_, address token1_, uint24 fee_, int24 tickSpacing_)
      public
      virtual
      override
  {
      require(factory == address(1), "AII");  // Corrected check
      // Additional initialization code
  }
  ```



## Assessed type

DoS