New project which also creates a new uniswap pool could fail to launch due to the assumption that the price in uniswap's pool slot0 will remain same from the creation time of project to the launch time.
As uniswap pool is a public pool, price could change due to interactions leading to failure to launch of the project due to the below check at the time of launch.
As the launch has potential to fail, the claim is also not possible leading to locking of user funds.
The above check assumes that the configured price at the time of launch and price returned by the uniswap pool will remain the same, which is an incorrect assumption.
Proof of Concept
Anyone can initialize a project by calling initProject() function. As part of the initialization, the logic checks for existence of the pool in Uniswap factory and if not, creates a new pool in uniswap
and sets the initial sqrt price for the pool. One of the key parameter passed during the project creation is the launchTime which defines when the launch for the project can happen and when can the refund for the
pools under the project can be claimed.
All the key parameters are stored in the contract in _cachedProject mapping.
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);
}
The owner can then start adding pools using initILOPool() function.
At the time of launch, one of the key conditions being checked is if the configured price is equal to
Uniswap pool's slot 0 price. Incase the price does not match, the launch function will essentially revert.
Uniswap pool is a public accessible pool and any one should be able to interact with the Uniswap pool and move the price for the pair directly impacting the slot0 price.
This will lead to failure of launch of the project.
There is a time window between when the project was created and when it will be launched. The time difference leaves a natural opportunity for any one to interact with the newly created pool in uni-swap causing the price to shift in this mean time.
The change is price can be intentional by a bad actor front running the launch call or natural change in price as part of participation by external parties.
Tools Used
Manual review
Recommended Mitigation Steps
The assumption that price will remain same from creation of the project in the local contract storage and in Uni-swap pool is an incorrect assumption and hence the check should be removed. As public pool, the price has natural scope to move.
Lines of code
https://github.com/code-423n4/2024-06-vultisig/blob/cb72b1e9053c02a58d874ff376359a83dc3f0742/src/ILOManager.sol#L57-L65 https://github.com/code-423n4/2024-06-vultisig/blob/cb72b1e9053c02a58d874ff376359a83dc3f0742/src/ILOManager.sol#L187-L198
Vulnerability details
Impact
New project which also creates a new uniswap pool could fail to launch due to the assumption that the price in uniswap's pool slot0 will remain same from the creation time of project to the launch time.
As uniswap pool is a public pool, price could change due to interactions leading to failure to launch of the project due to the below check at the time of launch.
As the launch has potential to fail, the claim is also not possible leading to locking of user funds.
The above check assumes that the configured price at the time of launch and price returned by the uniswap pool will remain the same, which is an incorrect assumption.
Proof of Concept
Anyone can initialize a project by calling initProject() function. As part of the initialization, the logic checks for existence of the pool in Uniswap factory and if not, creates a new pool in uniswap and sets the initial sqrt price for the pool. One of the key parameter passed during the project creation is the launchTime which defines when the launch for the project can happen and when can the refund for the pools under the project can be claimed.
All the key parameters are stored in the contract in _cachedProject mapping.
The owner can then start adding pools using initILOPool() function.
At the time of launch, one of the key conditions being checked is if the configured price is equal to Uniswap pool's slot 0 price. Incase the price does not match, the launch function will essentially revert.
Uniswap pool is a public accessible pool and any one should be able to interact with the Uniswap pool and move the price for the pair directly impacting the slot0 price.
This will lead to failure of launch of the project.
There is a time window between when the project was created and when it will be launched. The time difference leaves a natural opportunity for any one to interact with the newly created pool in uni-swap causing the price to shift in this mean time.
The change is price can be intentional by a bad actor front running the launch call or natural change in price as part of participation by external parties.
Tools Used
Manual review
Recommended Mitigation Steps
The assumption that price will remain same from creation of the project in the local contract storage and in Uni-swap pool is an incorrect assumption and hence the check should be removed. As public pool, the price has natural scope to move.
Assessed type
Uniswap