ExponentialStrategy

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/strategies/ExponentialStrategy.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;

import "./ILiquidityStrategy.sol";
import "./LiquidityDistributionLibrary.sol";
import {TickMath} from "v4-core/libraries/TickMath.sol";
import {wadExp} from "solmate/src/utils/SignedWadMath.sol";
import {FullMath} from "v4-core/libraries/FullMath.sol";

/**
 * @title ExponentialStrategy
 * @notice Unified Exponential distribution strategy supporting all options
 * @dev Supports standard, carpeted, weighted, and weighted+carpeted variants
 */
contract ExponentialStrategy is ILiquidityStrategy {
    uint256 public constant CARPET_WEIGHT = 0.00005e18; // 0.005% carpet weight

    struct DensityParams {
        int24[] lowerTicks;
        int24[] upperTicks;
        int24 currentTick;
        int24 centerTick;
        uint24 ticksLeft;
        uint24 ticksRight;
        uint256 weight0;
        uint256 weight1;
        bool useCarpet;
        int24 tickSpacing;
        bool weightsAreProportional;
    }

    struct CarpetInfo {
        bool hasLeftCarpet;
        bool hasRightCarpet;
        uint256 startIdx;
        uint256 endIdx;
        uint256 numRanges;
    }


    /**
     * @notice Generate ranges with optional carpet positions
     * @dev Allows explicit control over carpet position generation
     */
    function generateRanges(
        int24 centerTick,
        uint24 ticksLeft,
        uint24 ticksRight,
        int24 tickSpacing,
        bool useCarpet
    ) external pure override returns (
        int24[] memory lowerTicks,
        int24[] memory upperTicks
    ) {
        return _generateRanges(centerTick, ticksLeft, ticksRight, tickSpacing, useCarpet);
    }

    function _generateRanges(
        int24 centerTick,
        uint24 ticksLeft,
        uint24 ticksRight,
        int24 tickSpacing,
        bool useCarpet
    ) internal pure returns (
        int24[] memory lowerTicks,
        int24[] memory upperTicks
    ) {
        // Align center tick to tick spacing
        centerTick = (centerTick / tickSpacing) * tickSpacing;

        // Calculate and clamp bounds
        int24 leftBound;
        int24 rightBound;
        {
            // Safe calculation for leftBound
            int256 tempLeft = int256(centerTick) - int256(uint256(ticksLeft));
            if (tempLeft < int256(type(int24).min)) {
                leftBound = type(int24).min;
            } else {
                leftBound = int24(tempLeft);
            }

            // Safe calculation for rightBound
            int256 tempRight = int256(centerTick) + int256(uint256(ticksRight));
            if (tempRight > int256(type(int24).max)) {
                rightBound = type(int24).max;
            } else {
                rightBound = int24(tempRight);
            }

            // Clamp to Uniswap v4's usable tick bounds BEFORE calculating width
            int24 minUsable = TickMath.minUsableTick(tickSpacing);
            int24 maxUsable = TickMath.maxUsableTick(tickSpacing);

            if (leftBound < minUsable) leftBound = minUsable;
            if (rightBound > maxUsable) rightBound = maxUsable;
        }

        // Calculate width from actual span
        int24 width;
        {
            uint256 actualSpan = uint256(int256(rightBound) - int256(leftBound));
            uint256 divisor = 20 * uint24(tickSpacing);
            width = int24(uint24(((actualSpan + divisor - 1) / divisor) * uint24(tickSpacing)));
            if (width < tickSpacing) width = tickSpacing;
        }

        // Align bounds to width
        leftBound = (leftBound / width) * width;
        rightBound = (rightBound / width) * width;

        // Ensure bounds stay within usable range after alignment
        {
            int24 minUsable = TickMath.minUsableTick(tickSpacing);
            int24 maxUsable = TickMath.maxUsableTick(tickSpacing);
            if (leftBound < minUsable) leftBound = minUsable;
            if (rightBound > maxUsable) rightBound = maxUsable;
        }

        if (useCarpet) {
            return _generateRangesWithCarpet(leftBound, rightBound, width, tickSpacing);
        } else {
            return _generateStandardRanges(leftBound, rightBound, width);
        }
    }

    function _generateStandardRanges(
        int24 leftBound,
        int24 rightBound,
        int24 width
    ) private pure returns (
        int24[] memory lowerTicks,
        int24[] memory upperTicks
    ) {
        // Count how many ranges we'll create
        uint256 numRanges;
        int256 currentInt = int256(leftBound);
        int256 rightBoundInt = int256(rightBound);
        int256 widthInt = int256(uint256(int256(width)));
        while (currentInt < rightBoundInt) {
            unchecked {
                ++numRanges;
            }
            currentInt += widthInt;
        }

        // Allocate arrays
        lowerTicks = new int24[](numRanges);
        upperTicks = new int24[](numRanges);

        // Generate non-overlapping ranges
        int24 current = leftBound;
        for (uint256 i = 0; i < numRanges; ) {
            lowerTicks[i] = current;

            // Safe addition to avoid overflow
            int256 nextUpper = int256(current) + int256(uint256(int256(width)));
            if (nextUpper > int256(type(int24).max)) {
                upperTicks[i] = type(int24).max;
            } else {
                upperTicks[i] = int24(nextUpper);
            }

            // Ensure we don't exceed right bound
            if (upperTicks[i] > rightBound) {
                upperTicks[i] = rightBound;
            }

            // Safe addition for loop increment
            int256 nextCurrent = int256(current) + int256(uint256(int256(width)));
            if (nextCurrent <= int256(type(int24).max)) {
                current = int24(nextCurrent);
            } else {
                break; // Exit loop if we would overflow
            }
            unchecked { ++i; }
        }
    }

    function _generateRangesWithCarpet(
        int24 leftBound,
        int24 rightBound,
        int24 width,
        int24 tickSpacing
    ) private pure returns (
        int24[] memory lowerTicks,
        int24[] memory upperTicks
    ) {
        // Get base ranges first
        (int24[] memory baseLowers, int24[] memory baseUppers) = _generateStandardRanges(leftBound, rightBound, width);

        // Get usable tick bounds
        int24 minUsable = TickMath.minUsableTick(tickSpacing);
        int24 maxUsable = TickMath.maxUsableTick(tickSpacing);

        // Check if we need carpet ranges
        bool hasLeftCarpet = baseLowers[0] > minUsable;
        bool hasRightCarpet = baseUppers[baseUppers.length - 1] < maxUsable;

        // Calculate total number of ranges
        uint256 numCarpetRanges;
        if (hasLeftCarpet) {
            unchecked {
                ++numCarpetRanges;
            }
        }
        if (hasRightCarpet) {
            unchecked {
                ++numCarpetRanges;
            }
        }

        uint256 totalRanges = baseLowers.length + numCarpetRanges;
        lowerTicks = new int24[](totalRanges);
        upperTicks = new int24[](totalRanges);

        uint256 idx;

        // Add left carpet if needed
        if (hasLeftCarpet) {
            lowerTicks[idx] = minUsable;
            upperTicks[idx] = baseLowers[0];
            unchecked {
                ++idx;
            }
        }

        // Add base ranges
        uint256 baseLength = baseLowers.length;
        for (uint256 i = 0; i < baseLength; ) {
            lowerTicks[idx] = baseLowers[i];
            upperTicks[idx] = baseUppers[i];
            unchecked {
                ++idx;
                ++i;
            }
        }

        // Add right carpet if needed
        if (hasRightCarpet) {
            lowerTicks[idx] = baseUppers[baseUppers.length - 1];
            upperTicks[idx] = maxUsable;
        }
    }



    /**
     * @notice Calculate Exponential density with all options
     */
    function calculateDensities(
        int24[] memory lowerTicks,
        int24[] memory upperTicks,
        int24 currentTick,
        int24 centerTick,
        uint24 ticksLeft,
        uint24 ticksRight,
        uint256 weight0,
        uint256 weight1,
        bool useCarpet,
        int24 tickSpacing,
        bool weightsAreProportional
    ) public pure override returns (uint256[] memory weights) {
        DensityParams memory params = DensityParams({
            lowerTicks: lowerTicks,
            upperTicks: upperTicks,
            currentTick: currentTick,
            centerTick: centerTick,
            ticksLeft: ticksLeft,
            ticksRight: ticksRight,
            weight0: weight0,
            weight1: weight1,
            useCarpet: useCarpet,
            tickSpacing: tickSpacing,
            weightsAreProportional: weightsAreProportional
        });

        return _calculateDensitiesInternal(params);
    }

    function _calculateDensitiesInternal(
        DensityParams memory params
    ) private pure returns (uint256[] memory weights) {
        uint256 numRanges = params.lowerTicks.length;
        weights = new uint256[](numRanges);

        if (numRanges == 0) return weights;

        // Validate weights sum to 1e18 (skip for proportional weights)
        if (!params.weightsAreProportional) {
            require(params.weight0 + params.weight1 == 1e18, "Weights must sum to 1e18");
        }

        if (params.useCarpet) {
            _processWeightsWithCarpet(weights, params);
        } else {
            _processWeightsNoCarpet(weights, params);
        }

        return weights;
    }

    function _processWeightsNoCarpet(
        uint256[] memory weights,
        DensityParams memory params
    ) private pure {
        uint256 numRanges = params.lowerTicks.length;

        // Calculate lambda parameters for exponential decay
        uint256 lambdaLeft = uint256(params.ticksLeft) / 3;
        uint256 lambdaRight = uint256(params.ticksRight) / 3;

        if (lambdaLeft == 0) lambdaLeft = 1;
        if (lambdaRight == 0) lambdaRight = 1;

        // Calculate base exponential weights
        uint256[] memory baseWeights = new uint256[](numRanges);
        uint256 totalBaseWeight;

        for (uint256 i = 0; i < numRanges; ) {
            // Calculate midpoint of range (safe to prevent overflow)
            int256 midpointInt = (int256(params.lowerTicks[i]) + int256(params.upperTicks[i])) / 2;
            int24 midpoint = int24(midpointInt);

            // Calculate distance from center
            int256 distance = int256(midpoint) - int256(params.centerTick);
            uint256 absDistance = distance < 0 ? uint256(-distance) : uint256(distance);

            // Use appropriate lambda based on side
            uint256 lambda = distance < 0 ? lambdaLeft : lambdaRight;

            // Apply true exponential formula: exp(-absDistance/lambda)
            // wadExp expects input in WAD (1e18) format
            // We need to compute exp(-absDistance/lambda) = exp(-(absDistance * 1e18) / (lambda * 1e18))
            uint256 weight;
            if (absDistance < lambda * 10) { // Cutoff at 10*lambda for negligible weights
                // Calculate -absDistance/lambda in WAD format
                int256 exponent = -int256((absDistance * 1e18) / lambda);
                // wadExp returns exp(x) where x is in WAD format
                int256 expResult = wadExp(exponent);
                // Convert back to uint256, clamping negative values to 0
                weight = expResult > 0 ? uint256(expResult) : 0;
            } else {
                weight = 0; // Negligible weight far from center
            }

            baseWeights[i] = weight;
            unchecked {
                totalBaseWeight += weight;
                ++i;
            }
        }

        // Apply weight preferences
        if (params.weightsAreProportional) {
            // Proportional weights: use base distribution (no filtering)
            if (totalBaseWeight != 0) {
                for (uint256 i = 0; i < numRanges; ) {
                    weights[i] = FullMath.mulDiv(baseWeights[i], LiquidityDistributionLibrary.WAD, totalBaseWeight);
                    unchecked { ++i; }
                }
            }
        } else {
            // Explicit preferences: apply weight-based filtering
            uint256[] memory adjustedWeights = new uint256[](numRanges);
            uint256 totalAdjustedWeight;

            for (uint256 i = 0; i < numRanges; ) {
                if (params.upperTicks[i] <= params.currentTick) {
                    adjustedWeights[i] = FullMath.mulDiv(baseWeights[i] * params.weight1, 2, 1e18);
                } else if (params.lowerTicks[i] >= params.currentTick) {
                    adjustedWeights[i] = FullMath.mulDiv(baseWeights[i] * params.weight0, 2, 1e18);
                } else {
                    adjustedWeights[i] = baseWeights[i];
                }
                unchecked {
                    totalAdjustedWeight += adjustedWeights[i];
                    ++i;
                }
            }

            // Normalize to sum to 1e18
            if (totalAdjustedWeight != 0) {
                for (uint256 i = 0; i < numRanges; ) {
                    weights[i] = FullMath.mulDiv(adjustedWeights[i], LiquidityDistributionLibrary.WAD, totalAdjustedWeight);
                    unchecked { ++i; }
                }
            }
        }
    }

    function _processWeightsWithCarpet(
        uint256[] memory weights,
        DensityParams memory params
    ) private pure {
        _processWeightsWithCarpetPhase1(weights, params);
    }

    function _processWeightsWithCarpetPhase1(
        uint256[] memory weights,
        DensityParams memory params
    ) private pure {
        uint256 numRanges = params.lowerTicks.length;

        // Use the tick spacing from params instead of inferring
        int24 tickSpacing = params.tickSpacing;

        (bool hasLeftCarpet, bool hasRightCarpet, uint256 startIdx, uint256 endIdx) =
            _getCarpetInfo(params.lowerTicks, params.upperTicks, numRanges, tickSpacing);

        // Calculate lambda parameters
        uint256 lambdaLeft = uint256(params.ticksLeft) / 3;
        uint256 lambdaRight = uint256(params.ticksRight) / 3;

        if (lambdaLeft == 0) lambdaLeft = 1;
        if (lambdaRight == 0) lambdaRight = 1;

        // Calculate base and adjusted weights
        (uint256[] memory adjustedWeights, uint256 totalAdjustedWeight) = _calculateExponentialWeights(
            params,
            startIdx,
            endIdx,
            lambdaLeft,
            lambdaRight
        );

        // Store carpet info in a struct to reduce parameters
        CarpetInfo memory carpetInfo = CarpetInfo({
            hasLeftCarpet: hasLeftCarpet,
            hasRightCarpet: hasRightCarpet,
            startIdx: startIdx,
            endIdx: endIdx,
            numRanges: numRanges
        });

        // Finalize carpet weights
        _finalizeCarpetWeights(
            weights,
            adjustedWeights,
            totalAdjustedWeight,
            carpetInfo
        );
    }

    function _getCarpetInfo(
        int24[] memory lowerTicks,
        int24[] memory upperTicks,
        uint256 numRanges,
        int24 tickSpacing
    ) private pure returns (
        bool hasLeftCarpet,
        bool hasRightCarpet,
        uint256 startIdx,
        uint256 endIdx
    ) {
        int24 minUsable = TickMath.minUsableTick(tickSpacing);
        int24 maxUsable = TickMath.maxUsableTick(tickSpacing);

        hasLeftCarpet = lowerTicks[0] == minUsable;
        hasRightCarpet = upperTicks[numRanges - 1] == maxUsable;

        startIdx = hasLeftCarpet ? 1 : 0;
        endIdx = hasRightCarpet ? numRanges - 1 : numRanges;
    }

    function _calculateExponentialWeights(
        DensityParams memory params,
        uint256 startIdx,
        uint256 endIdx,
        uint256 lambdaLeft,
        uint256 lambdaRight
    ) private pure returns (uint256[] memory adjustedWeights, uint256 totalAdjustedWeight) {
        uint256 numRanges = params.lowerTicks.length;
        uint256[] memory baseWeights = new uint256[](numRanges);
        uint256 totalBaseWeight;

        // Calculate base exponential weights for main ranges
        for (uint256 i = startIdx; i < endIdx; ) {
            int256 midpointInt = (int256(params.lowerTicks[i]) + int256(params.upperTicks[i])) / 2;
            int24 midpoint = int24(midpointInt);
            int256 distance = int256(midpoint) - int256(params.centerTick);
            uint256 absDistance = distance < 0 ? uint256(-distance) : uint256(distance);

            uint256 lambda = distance < 0 ? lambdaLeft : lambdaRight;

            // Apply true exponential formula: exp(-absDistance/lambda)
            uint256 weight;
            if (absDistance < lambda * 10) { // Cutoff at 10*lambda for negligible weights
                // Calculate -absDistance/lambda in WAD format
                int256 exponent = -int256((absDistance * 1e18) / lambda);
                // wadExp returns exp(x) where x is in WAD format
                int256 expResult = wadExp(exponent);
                // Convert back to uint256, clamping negative values to 0
                weight = expResult > 0 ? uint256(expResult) : 0;
            } else {
                weight = 0; // Negligible weight far from center
            }

            baseWeights[i] = weight;
            unchecked {
                totalBaseWeight += weight;
                ++i;
            }
        }

        // Apply weight preferences to main ranges
        adjustedWeights = new uint256[](numRanges);

        if (params.weightsAreProportional) {
            // Proportional weights: use base distribution (no filtering)
            for (uint256 i = startIdx; i < endIdx; ) {
                adjustedWeights[i] = baseWeights[i];
                unchecked {
                    totalAdjustedWeight += adjustedWeights[i];
                    ++i;
                }
            }
        } else {
            // Explicit preferences: apply weight-based filtering
            for (uint256 i = startIdx; i < endIdx; ) {
                if (params.upperTicks[i] <= params.currentTick) {
                    adjustedWeights[i] = FullMath.mulDiv(baseWeights[i] * params.weight1, 2, 1e18);
                } else if (params.lowerTicks[i] >= params.currentTick) {
                    adjustedWeights[i] = FullMath.mulDiv(baseWeights[i] * params.weight0, 2, 1e18);
                } else {
                    adjustedWeights[i] = baseWeights[i];
                }
                unchecked {
                    totalAdjustedWeight += adjustedWeights[i];
                    ++i;
                }
            }
        }
    }

    function _finalizeCarpetWeights(
        uint256[] memory weights,
        uint256[] memory adjustedWeights,
        uint256 totalAdjustedWeight,
        CarpetInfo memory carpetInfo
    ) private pure {
        uint256 numCarpetRanges;
        if (carpetInfo.hasLeftCarpet) {
            unchecked {
                ++numCarpetRanges;
            }
        }
        if (carpetInfo.hasRightCarpet) {
            unchecked {
                ++numCarpetRanges;
            }
        }

        // Only subtract CARPET_WEIGHT if we actually have carpet ranges
        uint256 carpetWeightPerRange = numCarpetRanges != 0 ? CARPET_WEIGHT / numCarpetRanges : 0;
        uint256 remainingWeight = numCarpetRanges != 0 ?
            LiquidityDistributionLibrary.WAD - CARPET_WEIGHT :
            LiquidityDistributionLibrary.WAD;

        if (carpetInfo.hasLeftCarpet) {
            weights[0] = carpetWeightPerRange;
        }
        if (carpetInfo.hasRightCarpet) {
            weights[carpetInfo.numRanges - 1] = carpetWeightPerRange;
        }

        // Normalize main range weights
        if (totalAdjustedWeight != 0) {
            for (uint256 i = carpetInfo.startIdx; i < carpetInfo.endIdx; ) {
                weights[i] = FullMath.mulDiv(adjustedWeights[i], remainingWeight, totalAdjustedWeight);
                unchecked { ++i; }
            }
        }
    }


    /**
     * @notice This strategy supports weighted distribution
     */
    function supportsWeights() external pure override returns (bool) {
        return true;
    }

    /**
     * @notice Get strategy type identifier
     */
    function getStrategyType() external pure override returns (string memory) {
        return "Exponential";
    }

    /**
     * @notice Get human-readable description
     */
    function getDescription() external pure override returns (string memory) {
        return "Exponential distribution with optional carpet and weight preferences";
    }
}"
    },
    "src/strategies/ILiquidityStrategy.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;

/**
 * @title ILiquidityStrategy
 * @notice Interface for liquidity distribution strategies matching Python shapes
 * @dev Each strategy implements a different distribution pattern (uniform, triangle, gaussian, etc.)
 */
interface ILiquidityStrategy {
    /**
     * @notice Generate tick ranges with optional carpet positions
     * @param centerTick The center tick for the strategy
     * @param ticksLeft Number of ticks to the left of center for the distribution
     * @param ticksRight Number of ticks to the right of center for the distribution
     * @param tickSpacing The tick spacing of the pool
     * @param useCarpet Whether to add carpet positions at extreme ticks for TWAP support
     * @return lowerTicks Array of lower ticks for each position
     * @return upperTicks Array of upper ticks for each position
     */
    function generateRanges(
        int24 centerTick,
        uint24 ticksLeft,
        uint24 ticksRight,
        int24 tickSpacing,
        bool useCarpet
    ) external view returns (
        int24[] memory lowerTicks,
        int24[] memory upperTicks
    );

    /**
     * @notice Get the strategy type identifier
     * @return strategyType String identifier for the strategy (e.g., "uniform", "triangle", "gaussian")
     */
    function getStrategyType() external view returns (string memory strategyType);
    
    /**
     * @notice Get a description of the strategy
     * @return description Human-readable description of the distribution pattern
     */
    function getDescription() external view returns (string memory description);

    /**
     * @notice Check if this strategy supports weighted distribution
     * @return supported True if the strategy implements calculateDensitiesWithWeights
     */
    function supportsWeights() external pure returns (bool supported);

    /**
     * @notice Calculate density weights with token weights and carpet options
     * @dev Comprehensive function that supports both token weights and carpet liquidity
     * @param lowerTicks Array of lower ticks for each position
     * @param upperTicks Array of upper ticks for each position
     * @param currentTick Current tick of the pool
     * @param centerTick Center tick for the distribution
     * @param ticksLeft Number of ticks to the left of center for the shape
     * @param ticksRight Number of ticks to the right of center for the shape
     * @param weight0 Weight preference for token0 (scaled to 1e18, e.g., 0.8e18 for 80%)
     * @param weight1 Weight preference for token1 (scaled to 1e18, e.g., 0.2e18 for 20%)
     * @param useCarpet Whether to add carpet liquidity at extremes (0.01% each)
     * @param tickSpacing The tick spacing of the pool
     * @param weightsAreProportional True if weights were auto-calculated from available tokens (should not filter ranges)
     * @return weights Array of weights for each position (scaled to 1e18, sum = 1e18)
     */
    function calculateDensities(
        int24[] memory lowerTicks,
        int24[] memory upperTicks,
        int24 currentTick,
        int24 centerTick,
        uint24 ticksLeft,
        uint24 ticksRight,
        uint256 weight0,
        uint256 weight1,
        bool useCarpet,
        int24 tickSpacing,
        bool weightsAreProportional
    ) external view returns (uint256[] memory weights);
}"
    },
    "src/strategies/LiquidityDistributionLibrary.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;

import {wadExp} from "solmate/src/utils/SignedWadMath.sol";

/**
 * @title LiquidityDistributionLibrary
 * @notice Library for mathematical functions used in liquidity distribution strategies
 * @dev Implements approximations for exp, gaussian, and other mathematical functions
 */
library LiquidityDistributionLibrary {
    uint256 constant WAD = 1e18;
    uint256 constant HALF_WAD = 5e17;
    
    /**
     * @notice Calculate the absolute difference between two int24 values
     * @param a First value
     * @param b Second value
     * @return The absolute difference as uint256
     */
    function absDiff(int24 a, int24 b) internal pure returns (uint256) {
        return a > b ? uint256(int256(a - b)) : uint256(int256(b - a));
    }
    
    /**
     * @notice Calculate the center tick of a position
     * @param lowerTick Lower tick of the position
     * @param upperTick Upper tick of the position
     * @return Center tick of the position
     */
    function centerTick(int24 lowerTick, int24 upperTick) internal pure returns (int24) {
        return (lowerTick + upperTick) / 2;
    }
    
    /**
     * @notice Approximate exponential function using Taylor series
     * @dev exp(x) ≈ 1 + x + x²/2 + x³/6 + x⁴/24 for small x
     * @param x Input scaled by WAD (negative values for decay)
     * @return Approximation of exp(x) scaled by WAD
     */
    function exp(int256 x) internal pure returns (uint256) {
        // Use solmate's wadExp for precise exponential calculation
        int256 result = wadExp(x);
        // Convert to uint256, ensuring non-negative
        return result > 0 ? uint256(result) : 0;
    }
    
    /**
     * @notice Calculate gaussian-like density
     * @dev Uses exp(-(x²/2σ²)) approximation
     * @param distance Distance from center (absolute value)
     * @param sigma Standard deviation scaled by WAD
     * @return Gaussian density value scaled by WAD
     */
    function gaussian(uint256 distance, uint256 sigma) internal pure returns (uint256) {
        if (sigma == 0) return distance == 0 ? WAD : 0;
        
        // Calculate -(distance²)/(2σ²)
        // Scale down to prevent overflow
        uint256 scaledDist = (distance * WAD) / sigma;
        
        // If distance is too large, return minimal value
        if (scaledDist > 3 * WAD) return 1; // Beyond 3 sigma
        
        // Calculate exp(-(scaledDist²)/2)
        uint256 exponent = (scaledDist * scaledDist) / (2 * WAD);
        return exp(-int256(exponent));
    }
    
    /**
     * @notice Calculate triangle distribution density
     * @param distance Distance from center
     * @param maxDistance Maximum distance (triangle base)
     * @return Triangle density value scaled by WAD
     */
    function triangle(uint256 distance, uint256 maxDistance) internal pure returns (uint256) {
        if (maxDistance == 0 || distance >= maxDistance) return 0;
        
        // Linear decay from center: (1 - distance/maxDistance)
        return WAD - (distance * WAD) / maxDistance;
    }
    
    /**
     * @notice Calculate exponential distribution density
     * @param distance Distance from center
     * @param lambda Decay parameter scaled by WAD
     * @return Exponential density value scaled by WAD
     */
    function exponential(uint256 distance, uint256 lambda) internal pure returns (uint256) {
        if (lambda == 0) return distance == 0 ? WAD : 0;
        
        // Calculate exp(-distance/lambda)
        int256 exponent = -int256((distance * WAD) / lambda);
        return exp(exponent);
    }
    
    /**
     * @notice Normalize an array of weights to sum to WAD
     * @param weights Array of weights to normalize
     * @return normalized Array of normalized weights
     */
    function normalize(uint256[] memory weights) internal pure returns (uint256[] memory normalized) {
        uint256 length = weights.length;
        normalized = new uint256[](length);
        
        // Calculate sum
        uint256 sum;
        for (uint256 i = 0; i < length; ) {
            unchecked {
                sum += weights[i];
                ++i;
            }
        }
        
        // If sum is zero, distribute equally
        if (sum == 0) {
            uint256 equalWeight = WAD / length;
            uint256 remainder;
            unchecked {
                remainder = WAD - (equalWeight * length);
            }
            for (uint256 i = 0; i < length; ) {
                normalized[i] = equalWeight;
                if (i == length - 1) {
                    unchecked {
                        normalized[i] += remainder;
                    }
                }
                unchecked { ++i; }
            }
            return normalized;
        }
        
        // Normalize to sum = WAD
        uint256 normalizedSum;
        for (uint256 i = 0; i < length; ) {
            if (i == length - 1) {
                // Last element gets the remainder to ensure exact sum
                normalized[i] = WAD - normalizedSum;
            } else {
                normalized[i] = (weights[i] * WAD) / sum;
                unchecked {
                    normalizedSum += normalized[i];
                }
            }
            unchecked { ++i; }
        }
        
        return normalized;
    }
    
    /**
     * @notice Calculate camel distribution (double-peaked)
     * @param distance Distance from center
     * @param maxDistance Maximum distance
     * @param peakOffset Offset of peaks from center (as fraction of maxDistance)
     * @return Camel density value scaled by WAD
     */
    function camel(uint256 distance, uint256 maxDistance, uint256 peakOffset) internal pure returns (uint256) {
        if (maxDistance == 0) return 0;
        
        // Create two peaks at ±peakOffset from center
        uint256 leftPeak = (maxDistance * peakOffset) / WAD;
        uint256 rightPeak = leftPeak;
        
        // Calculate distance to nearest peak
        uint256 distToLeft = distance > leftPeak ? distance - leftPeak : leftPeak - distance;
        uint256 distToRight = distance > rightPeak ? distance - rightPeak : rightPeak - distance;
        uint256 minDist = distToLeft < distToRight ? distToLeft : distToRight;
        
        // Use gaussian-like decay from nearest peak
        uint256 sigma = maxDistance / 3;
        uint256 density = gaussian(minDist, sigma);
        
        // Add base level to connect the peaks
        return density + (WAD / 10); // Add 10% base level
    }
}"
    },
    "lib/v4-periphery/lib/v4-core/src/libraries/TickMath.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {BitMath} from "./BitMath.sol";
import {CustomRevert} from "./CustomRevert.sol";

/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
    using CustomRevert for bytes4;

    /// @notice Thrown when the tick passed to #getSqrtPriceAtTick is not between MIN_TICK and MAX_TICK
    error InvalidTick(int24 tick);
    /// @notice Thrown when the price passed to #getTickAtSqrtPrice does not correspond to a price between MIN_TICK and MAX_TICK
    error InvalidSqrtPrice(uint160 sqrtPriceX96);

    /// @dev The minimum tick that may be passed to #getSqrtPriceAtTick computed from log base 1.0001 of 2**-128
    /// @dev If ever MIN_TICK and MAX_TICK are not centered around 0, the absTick logic in getSqrtPriceAtTick cannot be used
    int24 internal constant MIN_TICK = -887272;
    /// @dev The maximum tick that may be passed to #getSqrtPriceAtTick computed from log base 1.0001 of 2**128
    /// @dev If ever MIN_TICK and MAX_TICK are not centered around 0, the absTick logic in getSqrtPriceAtTick cannot be used
    int24 internal constant MAX_TICK = 887272;

    /// @dev The minimum tick spacing value drawn from the range of type int16 that is greater than 0, i.e. min from the range [1, 32767]
    int24 internal constant MIN_TICK_SPACING = 1;
    /// @dev The maximum tick spacing value drawn from the range of type int16, i.e. max from the range [1, 32767]
    int24 internal constant MAX_TICK_SPACING = type(int16).max;

    /// @dev The minimum value that can be returned from #getSqrtPriceAtTick. Equivalent to getSqrtPriceAtTick(MIN_TICK)
    uint160 internal constant MIN_SQRT_PRICE = 4295128739;
    /// @dev The maximum value that can be returned from #getSqrtPriceAtTick. Equivalent to getSqrtPriceAtTick(MAX_TICK)
    uint160 internal constant MAX_SQRT_PRICE = 1461446703485210103287273052203988822378723970342;
    /// @dev A threshold used for optimized bounds check, equals `MAX_SQRT_PRICE - MIN_SQRT_PRICE - 1`
    uint160 internal constant MAX_SQRT_PRICE_MINUS_MIN_SQRT_PRICE_MINUS_ONE =
        1461446703485210103287273052203988822378723970342 - 4295128739 - 1;

    /// @notice Given a tickSpacing, compute the maximum usable tick
    function maxUsableTick(int24 tickSpacing) internal pure returns (int24) {
        unchecked {
            return (MAX_TICK / tickSpacing) * tickSpacing;
        }
    }

    /// @notice Given a tickSpacing, compute the minimum usable tick
    function minUsableTick(int24 tickSpacing) internal pure returns (int24) {
        unchecked {
            return (MIN_TICK / tickSpacing) * tickSpacing;
        }
    }

    /// @notice Calculates sqrt(1.0001^tick) * 2^96
    /// @dev Throws if |tick| > max tick
    /// @param tick The input tick for the above formula
    /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the price of the two assets (currency1/currency0)
    /// at the given tick
    function getSqrtPriceAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
        unchecked {
            uint256 absTick;
            assembly ("memory-safe") {
                tick := signextend(2, tick)
                // mask = 0 if tick >= 0 else -1 (all 1s)
                let mask := sar(255, tick)
                // if tick >= 0, |tick| = tick = 0 ^ tick
                // if tick < 0, |tick| = ~~|tick| = ~(-|tick| - 1) = ~(tick - 1) = (-1) ^ (tick - 1)
                // either way, |tick| = mask ^ (tick + mask)
                absTick := xor(mask, add(mask, tick))
            }

            if (absTick > uint256(int256(MAX_TICK))) InvalidTick.selector.revertWith(tick);

            // The tick is decomposed into bits, and for each bit with index i that is set, the product of 1/sqrt(1.0001^(2^i))
            // is calculated (using Q128.128). The constants used for this calculation are rounded to the nearest integer

            // Equivalent to:
            //     price = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
            //     or price = int(2**128 / sqrt(1.0001)) if (absTick & 0x1) else 1 << 128
            uint256 price;
            assembly ("memory-safe") {
                price := xor(shl(128, 1), mul(xor(shl(128, 1), 0xfffcb933bd6fad37aa2d162d1a594001), and(absTick, 0x1)))
            }
            if (absTick & 0x2 != 0) price = (price * 0xfff97272373d413259a46990580e213a) >> 128;
            if (absTick & 0x4 != 0) price = (price * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
            if (absTick & 0x8 != 0) price = (price * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
            if (absTick & 0x10 != 0) price = (price * 0xffcb9843d60f6159c9db58835c926644) >> 128;
            if (absTick & 0x20 != 0) price = (price * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
            if (absTick & 0x40 != 0) price = (price * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
            if (absTick & 0x80 != 0) price = (price * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
            if (absTick & 0x100 != 0) price = (price * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
            if (absTick & 0x200 != 0) price = (price * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
            if (absTick & 0x400 != 0) price = (price * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
            if (absTick & 0x800 != 0) price = (price * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
            if (absTick & 0x1000 != 0) price = (price * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
            if (absTick & 0x2000 != 0) price = (price * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
            if (absTick & 0x4000 != 0) price = (price * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
            if (absTick & 0x8000 != 0) price = (price * 0x31be135f97d08fd981231505542fcfa6) >> 128;
            if (absTick & 0x10000 != 0) price = (price * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
            if (absTick & 0x20000 != 0) price = (price * 0x5d6af8dedb81196699c329225ee604) >> 128;
            if (absTick & 0x40000 != 0) price = (price * 0x2216e584f5fa1ea926041bedfe98) >> 128;
            if (absTick & 0x80000 != 0) price = (price * 0x48a170391f7dc42444e8fa2) >> 128;

            assembly ("memory-safe") {
                // if (tick > 0) price = type(uint256).max / price;
                if sgt(tick, 0) { price := div(not(0), price) }

                // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
                // we then downcast because we know the result always fits within 160 bits due to our tick input constraint
                // we round up in the division so getTickAtSqrtPrice of the output price is always consistent
                // `sub(shl(32, 1), 1)` is `type(uint32).max`
                // `price + type(uint32).max` will not overflow because `price` fits in 192 bits
                sqrtPriceX96 := shr(32, add(price, sub(shl(32, 1), 1)))
            }
        }
    }

    /// @notice Calculates the greatest tick value such that getSqrtPriceAtTick(tick) <= sqrtPriceX96
    /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_PRICE, as MIN_SQRT_PRICE is the lowest value getSqrtPriceAtTick may
    /// ever return.
    /// @param sqrtPriceX96 The sqrt price for which to compute the tick as a Q64.96
    /// @return tick The greatest tick for which the getSqrtPriceAtTick(tick) is less than or equal to the input sqrtPriceX96
    function getTickAtSqrtPrice(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
        unchecked {
            // Equivalent: if (sqrtPriceX96 < MIN_SQRT_PRICE || sqrtPriceX96 >= MAX_SQRT_PRICE) revert InvalidSqrtPrice();
            // second inequality must be >= because the price can never reach the price at the max tick
            // if sqrtPriceX96 < MIN_SQRT_PRICE, the `sub` underflows and `gt` is true
            // if sqrtPriceX96 >= MAX_SQRT_PRICE, sqrtPriceX96 - MIN_SQRT_PRICE > MAX_SQRT_PRICE - MIN_SQRT_PRICE - 1
            if ((sqrtPriceX96 - MIN_SQRT_PRICE) > MAX_SQRT_PRICE_MINUS_MIN_SQRT_PRICE_MINUS_ONE) {
                InvalidSqrtPrice.selector.revertWith(sqrtPriceX96);
            }

            uint256 price = uint256(sqrtPriceX96) << 32;

            uint256 r = price;
            uint256 msb = BitMath.mostSignificantBit(r);

            if (msb >= 128) r = price >> (msb - 127);
            else r = price << (127 - msb);

            int256 log_2 = (int256(msb) - 128) << 64;

            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(63, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(62, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(61, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(60, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(59, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(58, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(57, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(56, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(55, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(54, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(53, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(52, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(51, f))
                r := shr(f, r)
            }
            assembly ("memory-safe") {
                r := shr(127, mul(r, r))
                let f := shr(128, r)
                log_2 := or(log_2, shl(50, f))
            }

            int256 log_sqrt10001 = log_2 * 255738958999603826347141; // Q22.128 number

            // Magic number represents the ceiling of the maximum value of the error when approximating log_sqrt10001(x)
            int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);

            // Magic number represents the minimum value of the error when approximating log_sqrt10001(x), when
            // sqrtPrice is from the range (2^-64, 2^64). This is safe as MIN_SQRT_PRICE is more than 2^-64. If MIN_SQRT_PRICE
            // is changed, this may need to be changed too
            int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);

            tick = tickLow == tickHi ? tickLow : getSqrtPriceAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
        }
    }
}
"
    },
    "lib/v4-periphery/lib/v4-core/lib/solmate/src/utils/SignedWadMath.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @notice Signed 18 decimal fixed point (wad) arithmetic library.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SignedWadMath.sol)
/// @author Modified from Remco Bloemen (https://xn--2-umb.com/22/exp-ln/index.html)

/// @dev Will not revert on overflow, only use where overflow is not possible.
function toWadUnsafe(uint256 x) pure returns (int256 r) {
    /// @solidity memory-safe-assembly
    assembly {
        // Multiply x by 1e18.
        r := mul(x, 1000000000000000000)
    }
}

/// @dev Takes an integer amount of seconds and converts it to a wad amount of days.
/// @dev Will not revert on overflow, only use where overflow is not possible.
/// @dev Not meant for negative second amounts, it assumes x is positive.
function toDaysWadUnsafe(uint256 x) pure returns (int256 r) {
    /// @solidity memory-safe-assembly
    assembly {
        // Multiply x by 1e18 and then divide it by 86400.
        r := div(mul(x, 1000000000000000000), 86400)
    }
}

/// @dev Takes a wad amount of days and converts it to an integer amount of seconds.
/// @dev Will not revert on overflow, only use where overflow is not possible.
/// @dev Not meant for negative day amounts, it assumes x is positive.
function fromDaysWadUnsafe(int256 x) pure returns (uint256 r) {
    /// @solidity memory-safe-assembly
    assembly {
        // Multiply x by 86400 and then divide it by 1e18.
        r := div(mul(x, 86400), 1000000000000000000)
    }
}

/// @dev Will not revert on overflow, only use where overflow is not possible.
function unsafeWadMul(int256 x, int256 y) pure returns (int256 r) {
    /// @solidity memory-safe-assembly
    assembly {
        // Multiply x by y and divide by 1e18.
        r := sdiv(mul(x, y), 1000000000000000000)
    }
}

/// @dev Will return 0 instead of reverting if y is zero and will
/// not revert on overflow, only use where overflow is not possible.
function unsafeWadDiv(int256 x, int256 y) pure returns (int256 r) {
    /// @solidity memory-safe-assembly
    assembly {
        // Multiply x by 1e18 and divide it by y.
        r := sdiv(mul(x, 1000000000000000000), y)
    }
}

function wadMul(int256 x, int256 y) pure returns (int256 r) {
    /// @solidity memory-safe-assembly
    assembly {
        // Store x * y in r for now.
        r := mul(x, y)

        // Combined overflow check (`x == 0 || (x * y) / x == y`) and edge case check
        // where x == -1 and y == type(int256).min, for y == -1 and x == min int256,
        // the second overflow check will catch this.
        // See: https://secure-contracts.com/learn_evm/arithmetic-checks.html#arithmetic-checks-for-int256-multiplication
        // Combining into 1 expression saves gas as resulting bytecode will only have 1 `JUMPI`
        // rather than 2.
        if iszero(
            and(
                or(iszero(x), eq(sdiv(r, x), y)),
                or(lt(x, not(0)), sgt(y, 0x8000000000000000000000000000000000000000000000000000000000000000))
            )
        ) {
            revert(0, 0)
        }

        // Scale the result down by 1e18.
        r := sdiv(r, 1000000000000000000)
    }
}

function wadDiv(int256 x, int256 y) pure returns (int256 r) {
    /// @solidity memory-safe-assembly
    assembly {
        // Store x * 1e18 in r for now.
        r := mul(x, 1000000000000000000)

        // Equivalent to require(y != 0 && ((x * 1e18) / 1e18 == x))
        if iszero(and(iszero(iszero(y)), eq(sdiv(r, 1000000000000000000), x))) {
            revert(0, 0)
        }

        // Divide r by y.
        r := sdiv(r, y)
    }
}

/// @dev Will not work with negative bases, only use when x is positive.
function wadPow(int256 x, int256 y) pure returns (int256) {
    // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)
    return wadExp((wadLn(x) * y) / 1e18); // Using ln(x) means x must be greater than 0.
}

function wadExp(int256 x) pure returns (int256 r) {
    unchecked {
        // When the result is < 0.5 we return zero. This happens when
        // x <= floor(log(0.5e18) * 1e18) ~ -42e18
        if (x <= -42139678854452767551) return 0;

        // When the result is > (2**255 - 1) / 1e18 we can not represent it as an
        // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
        if (x >= 135305999368893231589) revert("EXP_OVERFLOW");

        // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
        // for more intermediate precision and a binary basis. This base conversion
        // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
        x = (x << 78) / 5**18;

        // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
        // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
        // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
        int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
        x = x - k * 54916777467707473351141471128;

        // k is in the range [-61, 195].

        // Evaluate using a (6, 7)-term rational approximation.
        // p is made monic, we'll multiply by a scale factor later.
        int256 y = x + 1346386616545796478920950773328;
        y = ((y * x) >> 96) + 57155421227552351082224309758442;
        int256 p = y + x - 94201549194550492254356042504812;
        p = ((p * y) >> 96) + 28719021644029726153956944680412240;
        p = p * x + (4385272521454847904659076985693276 << 96);

        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
        int256 q = x - 2855989394907223263936484059900;
        q = ((q * x) >> 96) + 50020603652535783019961831881945;
        q = ((q * x) >> 96) - 533845033583426703283633433725380;
        q = ((q * x) >> 96) + 3604857256930695427073651918091429;
        q = ((q * x) >> 96) - 14423608567350463180887372962807573;
        q = ((q * x) >> 96) + 26449188498355588339934803723976023;

        /// @solidity memory-safe-assembly
        assembly {
            // Div in assembly because solidity adds a zero check despite the unchecked.
            // The q polynomial won't have zeros in the domain as all its roots are complex.
            // No scaling is necessary because p is already 2**96 too large.
            r := sdiv(p, q)
        }

        // r should be in the range (0.09, 0.25) * 2**96.

        // We now need to multiply r by:
        // * the scale factor s = ~6.031367120.
        // * the 2**k factor from the range reduction.
        // * the 1e18 / 2**96 factor for base conversion.
        // We do this all at once, with an intermediate result in 2**213
        // basis, so the final right shift is always by a positive amount.
        r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
    }
}

function wadLn(int256 x) pure returns (int256 r) {
    unchecked {
        require(x > 0, "UNDEFINED");

        // We want to convert x from 10**18 fixed point to 2**96 fixed point.
        // We do this by multiplying by 2**96 / 10**18. But since
        // ln(x * C) = ln(x) + ln(C), we can simply do nothing here
        // and add ln(2**96 / 10**18) at the end.

        /// @solidity memory-safe-assembly
        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            r := or(r, shl(2, lt(0xf, shr(r, x))))
            r := or(r, shl(1, lt(0x3, shr(r, x))))
            r := or(r, lt(0x1, shr(r, x)))
        }

        // Reduce range of x to (1, 2) * 2**96
        // ln(2^k * x) = k * ln(2) + ln(x)
        int256 k = r - 96;
        x <<= uint256(159 - k);
        x = int256(uint256(x) >> 159);

        // Evaluate using a (8, 8)-term rational approximation.
        // p is made monic, we will multiply by a scale factor later.
        int256 p = x + 3273285459638523848632254066296;
        p = ((p * x) >> 96) + 24828157081833163892658089445524;
        p = ((p * x) >> 96) + 43456485725739037958740375743393;
        p = ((p * x) >> 96) - 11111509109440967052023855526967;
        p = ((p * x) >> 96) - 45023709667254063763336534515857;
        p = ((p * x) >> 96) - 14706773417378608786704636184526;
        p = p * x - (795164235651350426258249787498 << 96);

        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
        // q is monic by convention.
        int256 q = x + 5573035233440673466300451813936;
        q = ((q * x) >> 96) + 71694874799317883764090561454958;
        q = ((q * x) >> 96) + 283447036172924575727196451306956;
        q = ((q * x) >> 96) + 401686690394027663651624208769553;
        q = ((q * x) >> 96) + 204048457590392012362485061816622;
        q = ((q * x) >> 96) + 31853899698501571402653359427138;
        q = ((q * x) >> 96) + 909429971244387300277376558375;
        /// @solidity memory-safe-assembly
        assembly {
            // Div in assembly because solidity adds a zero check despite the unchecked.
            // The q polynomial is known not to have zeros in the domain.
            // No scaling required because p is already 2**96 too large.
            r := sdiv(p, q)
        }

        // r is in the range (0, 0.125) * 2**96

        // Finalization, we need to:
        // * multiply by the scale factor s = 5.549…
        // * add ln(2**96 / 10**18)
        // * add k * ln(2)
        // * multiply by 10**18 / 2**96 = 5**18 >> 78

        // mul s * 5e18 * 2**96, base is now 5**18 * 2**192
        r *= 1677202110996718588342820967067443963516166;
        // add ln(2) * k * 5e18 * 2**192
        r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
        // add ln(2**96 / 10**18) * 5e18 * 2**192
        r += 600920179829731861736702779321621459595472258049074101567377883020018308;
        // base conversion: mul 2**18 / 2**192
        r >>= 174;
    }
}

/// @dev Will return 0 instead of reverting if y is zero.
function unsafeDiv(int256 x, int256 y) pure returns (int256 r) {
    /// @solidity memory-safe-assembly
    assembly {
        // Divide x by y.
        r := sdiv(x, y)
    }
}
"
    },
    "lib/v4-periphery/lib/v4-core/src/libraries/FullMath.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = a * b
            // Compute the product mod 2**256 and mod 2**256 - 1
            // then use the Chinese Remainder Theorem to reconstruct
            // the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2**256 + prod0
            uint256 prod0 = a * b; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly ("memory-safe") {
                let mm := mulmod(a, b, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Make sure the result is less than 2**256.
            // Also prevents denominator == 0
            require(denominator > prod1);

            // Handle non-overflow cases, 256 by 256 division
            if (prod1 == 0) {
                assembly ("memory-safe") {
                    result := div(prod0, denominator)
                }
                return result;
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0]
            // Compute remainder using mulmod
            uint256 remainder;
            assembly ("memory-safe") {
                remainder := mulmod(a, b, denominator)
            }
            // Subtract 256 bit number from 512 bit number
            assembly ("memory-safe") {
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator
            // Compute largest power of two divisor of denominator.
            // Always >= 1.
            uint256 twos = (0 - denominator) & denominator;
            // Divide denominator by power of two
            assembly ("memory-safe") {
                denominator := div(denominator, twos)
            }

            // Divide [prod1 prod0] by the factors of two
            assembly ("memory-safe") {
                prod0 := div(prod0, twos)
            }
            // Shift in bits from prod1 into prod0. For this we need
            // to flip `twos` such that it is 2**256 / twos.
            // If twos is zero, then it becomes one
            assembly ("memory-safe") {
                twos := add(div(sub(0, twos), twos), 1)
            }
            prod0 |= prod1 * twos;

            // Invert denominator mod 2**256
            // Now that denominator is an odd number, it has an inverse
            // modulo 2**256 such that denominator * inv = 1 mod 2**256.
            // Compute the inverse by starting with a seed that is correct
            // correct for four bits. That is, denominator * inv = 1 mod 2**4
            uint256 inv = (3 * denominator) ^ 2;
            // Now use Newton-Raphson iteration to improve the precision.
            // Thanks to Hensel's lifting lemma, this also works in modular
            // arithmetic, doubling the correct bits in each step.
            inv *= 2 - denominator * inv; // inverse mod 2**8
            inv *= 2 - denominator * inv; // inverse mod 2**16
            inv *= 2 - denominator * inv; // inverse mod 2**32
            inv *= 2 - denominator * inv; // inverse mod 2**64
            inv *= 2 - denominator * inv; // inverse mod 2**128
            inv *= 2 - denominator * inv; // inverse mod 2**256

            // Because the division is now exact we can divide by multiplying
            // with the modular inverse of denominator. This will give us the
            // correct result modulo 2**256. Since the preconditions guarantee
            // that the outcome is less than 2**256, this is the final result.
            // We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inv;
            return result;
        }
    }

    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    function mulDivRoundingUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            result = mulDiv(a, b, denominator);
            if (mulmod(a, b, denominator) != 0) {
                require(++result > 0);
            }
        }
    }
}
"
    },
    "lib/v4-periphery/lib/v4-core/src/libraries/BitMath.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title BitMath
/// @dev This library provides functionality for computing bit properties of an unsigned integer
/// @author Solady (https://github.com/Vectorized/solady/blob/8200a70e8dc2a77ecb074fc2e99a2a0d36547522/src/utils/LibBit.sol)
library BitMath {
    /// @notice Returns the index of the most significant bit of the number,
    ///     where the least significant bit is at index 0 and the most significant bit is at index 255
    /// @param x the value for which to compute the most significant bit, must be greater than 0
    /// @return r the index of the most significant bit
    function mostSignificantBit(uint256 x) internal pure returns (uint8 r) {
        require(x > 0);

        assembly ("memory-safe") {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // forgefmt: disable-next-item
            r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                0x0706060506020500060203020504000106050205030304010505030400000000))
        }
    }

    /// @notice Returns the index of the least significant bit of the number,
    ///     where the least significant bit is at index 0 and the most significant bit is at index 255
    /// @param x the value for which to compute the least significant bit, must be greater than 0
    /// @return r the index of the least significant bit
    function leastSignificantBit(uint256 x) internal pure returns (uint8 r) {
        require(x > 0);

        assembly ("memory-safe") {
            // Isolate the least significant bit.
            x := and(x, sub(0, x))
            // For the upper 3 bits of the result, use a De Bruijn-like lookup.
            // Credit to adhusson: https://blog.adhusson.com/cheap-find-first-set-evm/
            // forgefmt: disable-next-item
            r := shl(5, shr(252, shl(shl(2, shr(250, mul(x,
                0xb6db6db6ddddddddd34d34d349249249210842108c6318c639ce739cffffffff))),
                0x8040405543005266443200005020610674053026020000107506200176117077)))
            // For the lower 5 bits of the result, use a De Bruijn lookup.
            // forgefmt: disable-next-item
            r := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f),
                0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
        }
    }
}
"
    },
    "lib/v4-periphery/lib/v4-core/src/libraries/CustomRevert.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Library for reverting with custom errors efficiently
/// @notice Contains functions for reverting with custom errors with different argument types efficiently
/// @dev To use this library, declare `using CustomRevert for bytes4;` and replace `revert CustomError()` with
/// `CustomError.selector.revertWith()`
/// @dev The functions may tamper with the free memory pointer but it is fine since the call context is exited immediately
library CustomRevert {
    /// @dev ERC-7751 error for wrapping bubbled up reverts
    error WrappedError(address target, bytes4 selector, bytes reason, bytes details);

    /// @dev Reverts with the selector of a custom error in the scratch space
    function revertWith(bytes4 selector) internal pure {
        assembly ("memory-safe") {
            mstore(0, selector)
            revert(0, 0x04)
        }
    }

    /// @dev Reverts with a custom error with an address argument in the scratch space
    function revertWith(bytes4 selector, address addr) internal pure {
        assembly ("memory-safe") {
            mstore(0, selector)
            mstore(0x04, and(addr, 0xffffffffffffffffffffffffffffffffffffffff))
            revert(0, 0x24)
        }
    }

    /// @dev Reverts with a custom error with an int24 argument in the scratch space
    function revertWith(bytes4 selector, int24 value) internal pure {
        assembly ("memory-safe") {
            mstore(0, selector)
            mstore(0x04, signextend(2, value))
            revert(0,

Tags:
Multisig, Liquidity, Multi-Signature, Factory|addr:0x398389415595762cb75df141961ba6a5dd64cf5a|verified:true|block:23678283|tx:0x455bb33364c507d82716bd2b7f4637c0c6090878f000c120dc15521e5fafd49a|first_check:1761725910

Submitted on: 2025-10-29 09:18:31

Comments

Log in to comment.

No comments yet.