code-423n4 / 2024-06-vultisig-findings

2 stars 0 forks source link

DoS: The `initProject` function can be subject to a denial-of-service (DoS) attack if a malicious attacker creates a `WETH/VULT` pool on Uniswap V3 and initializes the initial price incorrectly earlier. #24

Closed c4-bot-4 closed 5 months ago

c4-bot-4 commented 5 months ago

Lines of code

https://github.com/code-423n4/2024-06-vultisig/blob/0957ff9e50441cd6de6b4f6e28c7ea93f5cffa85/src/ILOManager.sol#L57-L65

Vulnerability details

Impact

A malicious attacker can create WETH/VULT pools with different fees and initialize those pools incorrectly before the vaultsig team calls the initProject function. As a result, this function either reverts or the protocol team is unable to initialize the pools as they intended.

Proof of Concept

A protocol team initializes a project by calling the initProject function. This function initializes the Uniswap V3 pool(L63).

File: src\ILOManager.sol
57:     function initProject(InitProjectParams calldata params) external override afterInitialize() returns(address uniV3PoolAddress) {
58:         uint64 refundDeadline = params.launchTime + DEFAULT_DEADLINE_OFFSET;
59: 
60:         PoolAddress.PoolKey memory poolKey = PoolAddress.getPoolKey(params.saleToken, params.raiseToken, params.fee);
61:         uniV3PoolAddress = _initUniV3PoolIfNecessary(poolKey, params.initialPoolPriceX96);
62:         
63:         _cacheProject(uniV3PoolAddress, params.saleToken, params.raiseToken, params.fee, params.initialPoolPriceX96, params.launchTime, refundDeadline);
64:         emit ProjectCreated(uniV3PoolAddress, _cachedProject[uniV3PoolAddress]);
65:     }

The _initUniV3PoolIfNecessary function creates a WETH/VULT pool if it does not exist. If the pool exists, it gets the current price of the pool and initializes it if the price is 0. If the current price of the pool is not 0, it checks if the current price is equal to sqrtPriceX96, the value of InitProjectParams.

File: src\ILOManager.sol
109:     function _initUniV3PoolIfNecessary(PoolAddress.PoolKey memory poolKey, uint160 sqrtPriceX96) internal returns (address pool) {
110:         pool = IUniswapV3Factory(UNIV3_FACTORY).getPool(poolKey.token0, poolKey.token1, poolKey.fee);
111:         if (pool == address(0)) {
112:             pool = IUniswapV3Factory(UNIV3_FACTORY).createPool(poolKey.token0, poolKey.token1, poolKey.fee);
113:             IUniswapV3Pool(pool).initialize(sqrtPriceX96);
114:         } else {
115:             (uint160 sqrtPriceX96Existing, , , , , , ) = IUniswapV3Pool(pool).slot0();
116:             if (sqrtPriceX96Existing == 0) {
117:                 IUniswapV3Pool(pool).initialize(sqrtPriceX96);
118:             } else {
119:                 require(sqrtPriceX96Existing == sqrtPriceX96, "UV3P");
120:             }
121:         }
122:     }

If a malicious attacker creates WETH/VULT pools and initializes them with an incorrect price (not $0.03, as intended by the Vaultsig team) earlier than the protocol team, the _initUniV3PoolIfNecessary function can be subject to a denial-of-service (DoS) attack.

Tools Used

Manual Review

Recommended Mitigation Steps

The protocol team should create WETH/VULT pools and initialize them with proper prices via a deployer with the deployment of the Vult token contract.

Assessed type

DoS

c4-judge commented 4 months ago

alex-ppg marked the issue as unsatisfactory: Insufficient quality