`ILOManager::launch` erroneously requires that current pool ratio is the exact same as when the project was initialized, which can permanently DoS project launches
Audit: 2024-06-vultisig-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-vultisig/blob/main/src/ILOManager.sol#L109-L122
https://github.com/code-423n4/2024-06-vultisig/blob/main/src/ILOManager.sol#L187-L198


# Vulnerability details

## Impact
Users can create projects by calling `ILOManager::initProject` and specify the `project parameters`, including the project `launchTime` and `initialPoolPriceX96`.

The `initialPoolPriceX96` is set in two ways: Either from a newly created pool, or fetched from an existing pool via `slot0`.

For context, the `initialPoolPriceX96` represents the current ratio of reserves in the pool.

When the specified project `launch time` has passed, the project can be launched.

The problem is that there is a requirement that the current `sqrtPriceX96` of the pool must exactly match the `initialPoolPriceX96` that was set when the project was first created.

This value can change easily before the `launch time`, causing DoS to project launches.

## Proof of Concept
[ILOManager.sol#L109-L122](https://github.com/code-423n4/2024-06-vultisig/blob/main/src/ILOManager.sol#L109-L122)
```javascript
    function _initUniV3PoolIfNecessary(PoolAddress.PoolKey memory poolKey, uint160 sqrtPriceX96) internal returns (address pool) {
        pool = IUniswapV3Factory(UNIV3_FACTORY).getPool(poolKey.token0, poolKey.token1, poolKey.fee);
        if (pool == address(0)) {
            pool = IUniswapV3Factory(UNIV3_FACTORY).createPool(poolKey.token0, poolKey.token1, poolKey.fee);
            IUniswapV3Pool(pool).initialize(sqrtPriceX96);
        } else {
            (uint160 sqrtPriceX96Existing, , , , , , ) = IUniswapV3Pool(pool).slot0();
            if (sqrtPriceX96Existing == 0) {
                IUniswapV3Pool(pool).initialize(sqrtPriceX96);
            } else {
                require(sqrtPriceX96Existing == sqrtPriceX96, "UV3P");
            }
        }
    }
```

When pools are initialized, the `sqrtPriceX96` is fetched and stored. This value corresponds to the `initialPoolPriceX96` of the project.

Once the project `launchTime` has passed, the project can be launched.

[ILOManager.sol#L187-L198](https://github.com/code-423n4/2024-06-vultisig/blob/main/src/ILOManager.sol#L187-L198)
```javascript
    function launch(address uniV3PoolAddress) external override {
@>      require(block.timestamp > _cachedProject[uniV3PoolAddress].launchTime, "LT");
@>      (uint160 sqrtPriceX96, , , , , , ) = IUniswapV3Pool(uniV3PoolAddress).slot0();
@>      require(_cachedProject[uniV3PoolAddress].initialPoolPriceX96 == sqrtPriceX96, "UV3P");
        address[] memory initializedPools = _initializedILOPools[uniV3PoolAddress];
        require(initializedPools.length > 0, "NP");
        for (uint256 i = 0; i < initializedPools.length; i++) {
            IILOPool(initializedPools[i]).launch();
        }

        emit ProjectLaunch(uniV3PoolAddress);
    }
```

The function proceeds to fetch the `sqrtPriceX96` using `slot0` and compare it with the `initialPoolPriceX96` that was s