From 77aecf6445572d9f53c3c15df0fa1002378a813b Mon Sep 17 00:00:00 2001 From: rroland10 Date: Tue, 17 Feb 2026 09:18:58 -0600 Subject: [PATCH] fix: security audit fixes for PoolInitializer.sol Audit findings and fixes for PoolInitializer.createAndInitializePoolIfNecessary(): - V1: Add zero-address validation for all four token parameters (token0_20, token1_20, token0_223, token1_223) to prevent pool creation with invalid tokens - V2: Add descriptive revert reason to token ordering require (was bare require) - V3: Add sqrtPriceX96 != 0 validation to prevent initializing pools with an invalid zero price - V4: Add PoolCreatedAndInitialized event for off-chain observability - V5: Restore missing Revenue_old.sol and RevenueV1.sol compiler overrides in hardhat.config.ts (pre-existing build fix) Co-authored-by: Cursor --- .../dex-periphery/base/PoolInitializer.sol | 58 ++++++++++++++++++- hardhat.config.ts | 18 ++++++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/contracts/dex-periphery/base/PoolInitializer.sol b/contracts/dex-periphery/base/PoolInitializer.sol index 2cfdf26..f4cc620 100644 --- a/contracts/dex-periphery/base/PoolInitializer.sol +++ b/contracts/dex-periphery/base/PoolInitializer.sol @@ -8,8 +8,35 @@ import '../interfaces/IPoolInitializer.sol'; import './PeripheryImmutableState.sol'; /// @title Creates and initializes V3 Pools +/// @notice Provides input-validated pool creation and initialization for DEX-223. +/// @dev All token addresses and the initial price are validated before any +/// external call is made to the factory or pool contracts. abstract contract PoolInitializer is IPoolInitializer, PeripheryImmutableState { + + /// @notice Emitted when a pool is created and/or initialized through this contract + /// @param pool The address of the pool + /// @param token0_20 The ERC-20 address of token0 + /// @param token1_20 The ERC-20 address of token1 + /// @param fee The pool fee tier + /// @param sqrtPriceX96 The initial sqrt price (only meaningful when the pool was initialized) + /// @param created True if the pool was newly created, false if it already existed + /// @param initialized True if the pool was initialized in this call + event PoolCreatedAndInitialized( + address indexed pool, + address indexed token0_20, + address indexed token1_20, + uint24 fee, + uint160 sqrtPriceX96, + bool created, + bool initialized + ); + /// @inheritdoc IPoolInitializer + /// @dev Validates all inputs before making external calls: + /// - Token addresses must not be address(0). + /// - ERC-20 token0 must sort before token1 (standard Uniswap ordering). + /// - ERC-223 addresses must not be address(0) (prevents silent misconfiguration). + /// - sqrtPriceX96 must be non-zero (a zero value is an invalid Q64.96 price). function createAndInitializePoolIfNecessary( address token0_20, address token1_20, @@ -18,17 +45,44 @@ abstract contract PoolInitializer is IPoolInitializer, PeripheryImmutableState { uint24 fee, uint160 sqrtPriceX96 ) external payable override returns (address pool) { - require(token0_20 < token1_20); + // --- Input validation ------------------------------------------------ + + // V1: Zero-address checks for all token parameters + require(token0_20 != address(0), 'PI: ZERO_TOKEN0_20'); + require(token1_20 != address(0), 'PI: ZERO_TOKEN1_20'); + require(token0_223 != address(0), 'PI: ZERO_TOKEN0_223'); + require(token1_223 != address(0), 'PI: ZERO_TOKEN1_223'); + + // V2: Canonical ordering – token0 must sort before token1 + require(token0_20 < token1_20, 'PI: TOKEN_ORDER'); + + // V3: Initial price must be valid (zero is not a legal Q64.96 price) + require(sqrtPriceX96 > 0, 'PI: ZERO_PRICE'); + + // --- Pool lookup / creation ------------------------------------------ + pool = IDex223Factory(factory).getPool(token0_20, token1_20, fee); + bool created; + bool initialized; + if (pool == address(0)) { - pool = IDex223Factory(factory).createPool(token0_20, token1_20, token0_223, token1_223, fee); + pool = IDex223Factory(factory).createPool( + token0_20, token1_20, token0_223, token1_223, fee + ); IUniswapV3Pool(pool).initialize(sqrtPriceX96); + created = true; + initialized = true; } else { (uint160 sqrtPriceX96Existing, , , , , , ) = IUniswapV3Pool(pool).slot0(); if (sqrtPriceX96Existing == 0) { IUniswapV3Pool(pool).initialize(sqrtPriceX96); + initialized = true; } } + + emit PoolCreatedAndInitialized( + pool, token0_20, token1_20, fee, sqrtPriceX96, created, initialized + ); } } diff --git a/hardhat.config.ts b/hardhat.config.ts index 0e81066..3d382b1 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -123,6 +123,24 @@ const config: HardhatUserConfig = { } } }, + "contracts/dex-periphery/Revenue_old.sol": { + version: "0.8.19", + settings: { + optimizer: { + enabled: true, + runs: 5000, + } + } + }, + "contracts/dex-periphery/RevenueV1.sol": { + version: "0.8.19", + settings: { + optimizer: { + enabled: true, + runs: 5000, + } + } + }, } },