ETH Price: $2,920.10 (+4.01%)

Contract

0x3CF68E13e2813980a47957B4e360B49f965cbc1d

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x0c60211D...9201E4337
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
GaussianStrategy

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 800 runs

Other Settings:
cancun EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// 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 GaussianStrategy
 * @notice Gaussian distribution with center-aligned odd-number range generation
 * @dev Key features:
 *      1. Dynamic range count, forced odd - guarantees single center range
 *      2. Center-aligned grid: ranges are generated relative to centerTick, not 0
 *      3. Clamped ticksLeft/ticksRight for proper sigma calculation
 */
contract GaussianStrategy is ILiquidityStrategy {
    struct DensityParams {
        int24[] lowerTicks;
        int24[] upperTicks;
        int24 currentTick;
        int24 centerTick;
        uint24 ticksLeft;
        uint24 ticksRight;
        uint256 weight0;
        uint256 weight1;
        bool useCarpet;
        int24 tickSpacing;
        bool useAssetWeights;
    }

    /**
     * @notice Generate ranges with optional full-range floor position
     * @dev Uses center-aligned grid with odd number of ranges
     */
    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);
    }

    struct GridParams {
        int24 centerTick;
        int24 width;
        int24 leftBound;
        int24 rightBound;
        int24 minUsable;
        int24 maxUsable;
        uint256 numRanges;
    }

    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;

        GridParams memory grid = _calculateGridParams(centerTick, ticksLeft, ticksRight, tickSpacing);

        (int24[] memory baseLowers, int24[] memory baseUppers) =
            _generateStandardRanges(grid.leftBound, grid.rightBound, grid.width, centerTick);

        if (!useCarpet) {
            return (baseLowers, baseUppers);
        }

        return _prependFullRangeFloor(baseLowers, baseUppers, tickSpacing);
    }

    function _calculateGridParams(int24 centerTick, uint24 ticksLeft, uint24 ticksRight, int24 tickSpacing)
        private
        pure
        returns (GridParams memory grid)
    {
        grid.centerTick = centerTick;
        grid.minUsable = TickMath.minUsableTick(tickSpacing);
        grid.maxUsable = TickMath.maxUsableTick(tickSpacing);

        // Calculate raw bounds
        (int24 rawLeftBound, int24 rawRightBound) = _calculateRawBounds(centerTick, ticksLeft, ticksRight, grid.minUsable, grid.maxUsable);

        // Calculate width and numRanges dynamically
        (grid.width, grid.numRanges) = _calculateWidthAndNumRanges(rawLeftBound, rawRightBound, tickSpacing);

        // Calculate center-aligned bounds
        (grid.leftBound, grid.rightBound) = _calculateCenterAlignedBounds(
            centerTick, grid.width, grid.numRanges, tickSpacing, grid.minUsable, grid.maxUsable
        );
    }

    function _calculateRawBounds(int24 centerTick, uint24 ticksLeft, uint24 ticksRight, int24 minUsable, int24 maxUsable)
        private
        pure
        returns (int24 rawLeftBound, int24 rawRightBound)
    {
        int256 tempLeft = int256(centerTick) - int256(uint256(ticksLeft));
        rawLeftBound = tempLeft < int256(minUsable) ? minUsable : int24(tempLeft);

        int256 tempRight = int256(centerTick) + int256(uint256(ticksRight));
        rawRightBound = tempRight > int256(maxUsable) ? maxUsable : int24(tempRight);
    }

    function _calculateWidthAndNumRanges(int24 rawLeftBound, int24 rawRightBound, int24 tickSpacing)
        private
        pure
        returns (int24 width, uint256 numRanges)
    {
        uint256 actualSpan = uint256(int256(rawRightBound) - int256(rawLeftBound));

        // Calculate width (target ~20 ranges)
        uint256 targetRanges = 20;
        uint256 divisor = targetRanges * uint24(tickSpacing);
        width = int24(uint24(((actualSpan + divisor - 1) / divisor) * uint24(tickSpacing)));
        if (width < tickSpacing) width = tickSpacing;

        // Calculate actual number of ranges
        numRanges = actualSpan / uint256(int256(width));
        if (numRanges == 0) numRanges = 1;

        // If even, add 1 to make odd (guarantees single center range)
        if (numRanges % 2 == 0) {
            numRanges += 1;
        }
    }

    function _calculateCenterAlignedBounds(
        int24 centerTick,
        int24 width,
        uint256 numRanges,
        int24 tickSpacing,
        int24 minUsable,
        int24 maxUsable
    ) private pure returns (int24 leftBound, int24 rightBound) {
        // Clamp centerTick to usable bounds first to prevent overflow
        if (centerTick < minUsable) centerTick = minUsable;
        if (centerTick > maxUsable) centerTick = maxUsable;

        // Use int256 for intermediate calculations to prevent overflow
        int256 halfWidthInt = int256(width) / 2;
        int256 centerRangeLowerInt = int256(centerTick) - halfWidthInt;
        centerRangeLowerInt = (centerRangeLowerInt / int256(tickSpacing)) * int256(tickSpacing);
        int256 centerRangeUpperInt = centerRangeLowerInt + int256(width);

        // Calculate how many ranges on each side
        uint256 halfRanges = numRanges / 2;
        int256 widthInt = int256(uint256(int256(width)));

        // Left bound: start from centerRangeLower and go left by halfRanges
        int256 leftBoundInt = centerRangeLowerInt - int256(halfRanges) * widthInt;
        if (leftBoundInt < int256(minUsable)) leftBoundInt = int256(minUsable);
        leftBound = int24(leftBoundInt);

        // Right bound: start from centerRangeUpper and go right by halfRanges
        int256 rightBoundInt = centerRangeUpperInt + int256(halfRanges) * widthInt;
        if (rightBoundInt > int256(maxUsable)) rightBoundInt = int256(maxUsable);
        rightBound = int24(rightBoundInt);
    }

    function _generateStandardRanges(int24 leftBound, int24 rightBound, int24 width, int24 /* centerTick */)
        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;

            int256 nextUpper = int256(current) + int256(uint256(int256(width)));
            if (nextUpper > int256(type(int24).max)) {
                upperTicks[i] = type(int24).max;
            } else {
                upperTicks[i] = int24(nextUpper);
            }

            if (upperTicks[i] > rightBound) {
                upperTicks[i] = rightBound;
            }

            int256 nextCurrent = int256(current) + int256(uint256(int256(width)));
            if (nextCurrent <= int256(type(int24).max)) {
                current = int24(nextCurrent);
            } else {
                break;
            }
            unchecked {
                ++i;
            }
        }
    }

    function _prependFullRangeFloor(int24[] memory baseLowers, int24[] memory baseUppers, int24 tickSpacing)
        private
        pure
        returns (int24[] memory lowerTicks, int24[] memory upperTicks)
    {
        int24 minUsable = TickMath.minUsableTick(tickSpacing);
        int24 maxUsable = TickMath.maxUsableTick(tickSpacing);
        uint256 length = baseLowers.length;

        if (length == 0) {
            lowerTicks = new int24[](1);
            upperTicks = new int24[](1);
            lowerTicks[0] = minUsable;
            upperTicks[0] = maxUsable;
            return (lowerTicks, upperTicks);
        }

        uint256 floorIdx = type(uint256).max;
        for (uint256 i = 0; i < length; ++i) {
            if (_isFullRange(baseLowers[i], baseUppers[i], minUsable, maxUsable)) {
                floorIdx = i;
                break;
            }
        }

        if (floorIdx == 0) {
            return (baseLowers, baseUppers);
        }

        if (floorIdx == type(uint256).max) {
            lowerTicks = new int24[](length + 1);
            upperTicks = new int24[](length + 1);
            lowerTicks[0] = minUsable;
            upperTicks[0] = maxUsable;
            for (uint256 i = 0; i < length; ++i) {
                lowerTicks[i + 1] = baseLowers[i];
                upperTicks[i + 1] = baseUppers[i];
            }
            return (lowerTicks, upperTicks);
        }

        lowerTicks = new int24[](length);
        upperTicks = new int24[](length);
        lowerTicks[0] = minUsable;
        upperTicks[0] = maxUsable;

        uint256 idx = 1;
        for (uint256 i = 0; i < length; ++i) {
            if (i == floorIdx) {
                continue;
            }
            lowerTicks[idx] = baseLowers[i];
            upperTicks[idx] = baseUppers[i];
            unchecked {
                ++idx;
            }
        }
    }

    function _isFullRange(int24 lowerTick, int24 upperTick, int24 minUsable, int24 maxUsable)
        private
        pure
        returns (bool)
    {
        return lowerTick == minUsable && upperTick == maxUsable;
    }

    /**
     * @notice Calculate Gaussian 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 useAssetWeights
    ) 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,
            useAssetWeights: useAssetWeights
        });

        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;

        if (params.useCarpet && numRanges > 1) {
            int24 minUsable = TickMath.minUsableTick(params.tickSpacing);
            int24 maxUsable = TickMath.maxUsableTick(params.tickSpacing);
            if (params.lowerTicks[0] == minUsable && params.upperTicks[0] == maxUsable) {
                int24[] memory baseLower = new int24[](numRanges - 1);
                int24[] memory baseUpper = new int24[](numRanges - 1);
                for (uint256 i = 1; i < numRanges; ++i) {
                    baseLower[i - 1] = params.lowerTicks[i];
                    baseUpper[i - 1] = params.upperTicks[i];
                }

                DensityParams memory baseParams = params;
                baseParams.lowerTicks = baseLower;
                baseParams.upperTicks = baseUpper;

                uint256[] memory baseWeights = new uint256[](numRanges - 1);
                _processWeightsNoCarpet(baseWeights, baseParams);
                weights[0] = 0;
                for (uint256 i = 0; i < baseWeights.length; ++i) {
                    weights[i + 1] = baseWeights[i];
                }
                return weights;
            }
        }

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

        _processWeightsNoCarpet(weights, params);
        _applyFullRangeFloorWeight(weights, params);

        return weights;
    }

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

        // Find the center range (contains centerTick) to get BOTH bounds for symmetric distance calculation
        int24 centerRangeLower = params.centerTick; // fallback
        int24 centerRangeUpper = params.centerTick; // fallback
        for (uint256 i = 0; i < numRanges;) {
            if (params.lowerTicks[i] <= params.centerTick && params.centerTick < params.upperTicks[i]) {
                centerRangeLower = params.lowerTicks[i];
                centerRangeUpper = params.upperTicks[i];
                break;
            }
            unchecked { ++i; }
        }
        // Use the midpoint of the center range for symmetric distance calculation
        int24 centerMidpoint = (centerRangeLower + centerRangeUpper) / 2;

        // Calculate CLAMPED sigma based on actual range bounds (not requested ticksLeft/ticksRight)
        // This ensures proper decay when ticksLeft/ticksRight exceed minUsableTick/maxUsableTick
        uint256 sigmaLeft;
        uint256 sigmaRight;
        {
            // Symmetric: left uses centerRangeLower, right uses centerRangeUpper
            int256 leftSpan = int256(centerRangeLower) - int256(params.lowerTicks[0]);
            uint256 actualLeftSpan = leftSpan > 0 ? uint256(leftSpan) : 0;
            uint256 effectiveTicksLeft =
                actualLeftSpan < uint256(params.ticksLeft) ? actualLeftSpan : uint256(params.ticksLeft);

            int256 rightSpan = int256(params.upperTicks[numRanges - 1]) - int256(centerRangeUpper);
            uint256 actualRightSpan = rightSpan > 0 ? uint256(rightSpan) : 0;
            uint256 effectiveTicksRight =
                actualRightSpan < uint256(params.ticksRight) ? actualRightSpan : uint256(params.ticksRight);

            sigmaLeft = effectiveTicksLeft / 3;
            sigmaRight = effectiveTicksRight / 3;
        }
        if (sigmaLeft == 0) sigmaLeft = 1;
        if (sigmaRight == 0) sigmaRight = 1;

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

        for (uint256 i = 0; i < numRanges;) {
            bool isLeftOfCenter;
            uint256 absDistance;

            // Calculate distance from centerMidpoint to range's midpoint (not edge)
            // This ensures symmetric weights for both small and large ticksLeft/ticksRight
            int24 rangeMidpoint = (params.lowerTicks[i] + params.upperTicks[i]) / 2;
            int256 dist = int256(rangeMidpoint) - int256(centerMidpoint);
            absDistance = dist < 0 ? uint256(-dist) : uint256(dist);

            // Determine if left or right of center for sigma selection
            isLeftOfCenter = rangeMidpoint < centerMidpoint;

            // Use appropriate sigma based on side
            uint256 sigma = isLeftOfCenter ? sigmaLeft : sigmaRight;

            // Apply true Gaussian formula: exp(-0.5 * (distance/sigma)²)
            uint256 weight;
            if (absDistance < sigma * 6) {
                // 6-sigma covers 99.9997% of distribution
                // Normalize distance by sigma
                int256 normalizedDist = int256((absDistance * 1e18) / sigma);
                // Calculate -0.5 * (normalized_distance)²
                int256 exponent = -(normalizedDist * normalizedDist) / 2e18;
                // Apply exponential
                int256 expResult = wadExp(exponent);
                weight = expResult != 0 ? uint256(expResult) : 0;
            } else {
                weight = 0; // Beyond 6-sigma, negligible
            }

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

        // Apply weight preferences
        if (params.useAssetWeights) {
            // 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 _applyFullRangeFloorWeight(uint256[] memory weights, DensityParams memory params) private pure {
        if (!params.useCarpet || weights.length == 0) {
            return;
        }

        int24 minUsable = TickMath.minUsableTick(params.tickSpacing);
        int24 maxUsable = TickMath.maxUsableTick(params.tickSpacing);

        if (params.lowerTicks[0] != minUsable || params.upperTicks[0] != maxUsable) {
            return;
        }

        if (weights.length == 1) {
            weights[0] = LiquidityDistributionLibrary.WAD;
            return;
        }

        uint256 sum;
        for (uint256 i = 1; i < weights.length; ++i) {
            sum += weights[i];
        }

        if (sum == 0) {
            weights[0] = 0;
            return;
        }

        for (uint256 i = 1; i < weights.length; ++i) {
            weights[i] = FullMath.mulDiv(weights[i], LiquidityDistributionLibrary.WAD, sum);
        }
        weights[0] = 0;
    }

    /**
     * @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 "Gaussian";
    }

    /**
     * @notice Get human-readable description
     */
    function getDescription() external pure override returns (string memory) {
        return "Gaussian distribution with optional full-range floor and weight preferences";
    }
}

// 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 full-range floor position
     * @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 a full-range floor position (min/max usable ticks)
     * @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
        pure
        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 pure returns (string memory strategyType);

    /**
     * @notice Get a description of the strategy
     * @return description Human-readable description of the distribution pattern
     */
    function getDescription() external pure 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 optional full-range floor
     * @dev Comprehensive function that supports both token weights and full-range floor ranges
     * @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 a full-range floor position is present
     * @param tickSpacing The tick spacing of the pool
     * @param useAssetWeights 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 useAssetWeights
    ) external pure returns (uint256[] memory weights);
}

// 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
    }
}

// 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;
        }
    }
}

// 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)
    }
}

// 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);
            }
        }
    }
}

// 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))
        }
    }
}

// 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, 0x24)
        }
    }

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

    /// @dev Reverts with a custom error with two int24 arguments
    function revertWith(bytes4 selector, int24 value1, int24 value2) internal pure {
        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(fmp, selector)
            mstore(add(fmp, 0x04), signextend(2, value1))
            mstore(add(fmp, 0x24), signextend(2, value2))
            revert(fmp, 0x44)
        }
    }

    /// @dev Reverts with a custom error with two uint160 arguments
    function revertWith(bytes4 selector, uint160 value1, uint160 value2) internal pure {
        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(fmp, selector)
            mstore(add(fmp, 0x04), and(value1, 0xffffffffffffffffffffffffffffffffffffffff))
            mstore(add(fmp, 0x24), and(value2, 0xffffffffffffffffffffffffffffffffffffffff))
            revert(fmp, 0x44)
        }
    }

    /// @dev Reverts with a custom error with two address arguments
    function revertWith(bytes4 selector, address value1, address value2) internal pure {
        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(fmp, selector)
            mstore(add(fmp, 0x04), and(value1, 0xffffffffffffffffffffffffffffffffffffffff))
            mstore(add(fmp, 0x24), and(value2, 0xffffffffffffffffffffffffffffffffffffffff))
            revert(fmp, 0x44)
        }
    }

    /// @notice bubble up the revert message returned by a call and revert with a wrapped ERC-7751 error
    /// @dev this method can be vulnerable to revert data bombs
    function bubbleUpAndRevertWith(
        address revertingContract,
        bytes4 revertingFunctionSelector,
        bytes4 additionalContext
    ) internal pure {
        bytes4 wrappedErrorSelector = WrappedError.selector;
        assembly ("memory-safe") {
            // Ensure the size of the revert data is a multiple of 32 bytes
            let encodedDataSize := mul(div(add(returndatasize(), 31), 32), 32)

            let fmp := mload(0x40)

            // Encode wrapped error selector, address, function selector, offset, additional context, size, revert reason
            mstore(fmp, wrappedErrorSelector)
            mstore(add(fmp, 0x04), and(revertingContract, 0xffffffffffffffffffffffffffffffffffffffff))
            mstore(
                add(fmp, 0x24),
                and(revertingFunctionSelector, 0xffffffff00000000000000000000000000000000000000000000000000000000)
            )
            // offset revert reason
            mstore(add(fmp, 0x44), 0x80)
            // offset additional context
            mstore(add(fmp, 0x64), add(0xa0, encodedDataSize))
            // size revert reason
            mstore(add(fmp, 0x84), returndatasize())
            // revert reason
            returndatacopy(add(fmp, 0xa4), 0, returndatasize())
            // size additional context
            mstore(add(fmp, add(0xa4, encodedDataSize)), 0x04)
            // additional context
            mstore(
                add(fmp, add(0xc4, encodedDataSize)),
                and(additionalContext, 0xffffffff00000000000000000000000000000000000000000000000000000000)
            )
            revert(fmp, add(0xe4, encodedDataSize))
        }
    }
}

Settings
{
  "remappings": [
    "@ensdomains/=lib/v4-periphery/lib/v4-core/node_modules/@ensdomains/",
    "@openzeppelin/=lib/liquidity-launcher/lib/openzeppelin-contracts/",
    "@openzeppelin/contracts/=lib/liquidity-launcher/lib/openzeppelin-contracts/contracts/",
    "@openzeppelin-latest/=lib/liquidity-launcher/lib/openzeppelin-contracts/",
    "@optimism/=lib/liquidity-launcher/lib/optimism/packages/contracts-bedrock/",
    "@solady/=lib/liquidity-launcher/lib/solady/",
    "@uniswap/v4-core/=lib/v4-periphery/lib/v4-core/",
    "@uniswap/v4-periphery/=lib/v4-periphery/",
    "@uniswap/uerc20-factory/=lib/liquidity-launcher/lib/uerc20-factory/src/",
    "blocknumberish/=lib/liquidity-launcher/lib/blocknumberish/",
    "ds-test/=lib/v4-periphery/lib/v4-core/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/liquidity-launcher/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-gas-snapshot/=lib/v4-periphery/lib/forge-gas-snapshot/src/",
    "forge-std/=lib/forge-std/src/",
    "hardhat/=lib/v4-periphery/lib/v4-core/node_modules/hardhat/",
    "openzeppelin-contracts/=lib/liquidity-launcher/lib/openzeppelin-contracts/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "permit2/=lib/v4-periphery/lib/permit2/",
    "solady/=lib/liquidity-launcher/lib/solady/src/",
    "solmate/=lib/v4-periphery/lib/v4-core/lib/solmate/",
    "v4-core/=lib/v4-periphery/lib/v4-core/src/",
    "v4-periphery/=lib/v4-periphery/",
    "scripts/=lib/liquidity-launcher/lib/optimism/packages/contracts-bedrock/scripts/",
    "liquidity-launcher/src/token-factories/uerc20-factory/=lib/liquidity-launcher/lib/uerc20-factory/src/",
    "liquidity-launcher/src/=lib/liquidity-launcher/src/",
    "liquidity-launcher/=lib/liquidity-launcher/",
    "periphery/=lib/liquidity-launcher/src/periphery/",
    "continuous-clearing-auction/=lib/liquidity-launcher/lib/continuous-clearing-auction/",
    "ll/=lib/liquidity-launcher/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"int24[]","name":"lowerTicks","type":"int24[]"},{"internalType":"int24[]","name":"upperTicks","type":"int24[]"},{"internalType":"int24","name":"currentTick","type":"int24"},{"internalType":"int24","name":"centerTick","type":"int24"},{"internalType":"uint24","name":"ticksLeft","type":"uint24"},{"internalType":"uint24","name":"ticksRight","type":"uint24"},{"internalType":"uint256","name":"weight0","type":"uint256"},{"internalType":"uint256","name":"weight1","type":"uint256"},{"internalType":"bool","name":"useCarpet","type":"bool"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"bool","name":"useAssetWeights","type":"bool"}],"name":"calculateDensities","outputs":[{"internalType":"uint256[]","name":"weights","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"int24","name":"centerTick","type":"int24"},{"internalType":"uint24","name":"ticksLeft","type":"uint24"},{"internalType":"uint24","name":"ticksRight","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"bool","name":"useCarpet","type":"bool"}],"name":"generateRanges","outputs":[{"internalType":"int24[]","name":"lowerTicks","type":"int24[]"},{"internalType":"int24[]","name":"upperTicks","type":"int24[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getDescription","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getStrategyType","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"supportsWeights","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"}]

0x6080604052348015600e575f80fd5b50611ef98061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610064575f3560e01c80631b7c61411161004d5780631b7c6141146100bb57806340b71404146100db57806341717726146100fc575f80fd5b80630eb9b15a146100685780631a092541146100b3575b5f80fd5b60408051808201909152600881527f476175737369616e00000000000000000000000000000000000000000000000060208201525b6040516100aa9190611983565b60405180910390f35b61009d61010b565b6100ce6100c9366004611aa6565b61012b565b6040516100aa9190611b91565b6100ee6100e9366004611bd3565b6101ad565b6040516100aa929190611c71565b604051600181526020016100aa565b60606040518060800160405280604b8152602001611e79604b9139905090565b60605f6040518061016001604052808e81526020018d81526020018c60020b81526020018b60020b81526020018a62ffffff1681526020018962ffffff16815260200188815260200187815260200186151581526020018560020b8152602001841515815250905061019c816101cc565b9d9c50505050505050505050505050565b6060806101bd8787878787610583565b915091505b9550959350505050565b8051516060908067ffffffffffffffff8111156101eb576101eb6119b8565b604051908082528060200260200182016040528015610214578160200160208202803683370190505b509150805f036102245750919050565b82610100015180156102365750600181115b156104f0575f61024a8461012001516105f7565b90505f61025b856101200151610618565b90508160020b855f01515f8151811061027657610276611c95565b602002602001015160020b1480156102b057508060020b85602001515f815181106102a3576102a3611c95565b602002602001015160020b145b156104ed575f6102c1600185611cbd565b67ffffffffffffffff8111156102d9576102d96119b8565b604051908082528060200260200182016040528015610302578160200160208202803683370190505b5090505f610311600186611cbd565b67ffffffffffffffff811115610329576103296119b8565b604051908082528060200260200182016040528015610352578160200160208202803683370190505b50905060015b8581101561040557875180518290811061037457610374611c95565b60200260200101518360018361038a9190611cbd565b8151811061039a5761039a611c95565b602002602001019060020b908160020b81525050876020015181815181106103c4576103c4611c95565b6020026020010151826001836103da9190611cbd565b815181106103ea576103ea611c95565b60029290920b60209283029190910190910152600101610358565b5081875260208701819052865f61041d600188611cbd565b67ffffffffffffffff811115610435576104356119b8565b60405190808252806020026020018201604052801561045e578160200160208202803683370190505b50905061046b8183610630565b5f885f8151811061047e5761047e611c95565b6020026020010181815250505f5b81518110156104e0578181815181106104a7576104a7611c95565b6020026020010151898260016104bd9190611cd6565b815181106104cd576104cd611c95565b602090810291909101015260010161048c565b5050505050505050919050565b50505b826101400151610569578260e001518360c0015161050e9190611cd6565b670de0b6b3a7640000146105695760405162461bcd60e51b815260206004820152601860248201527f57656967687473206d7573742073756d20746f2031653138000000000000000060448201526064015b60405180910390fd5b6105738284610630565b61057d8284610c35565b50919050565b606080836105918189611cfd565b61059b9190611d35565b96505f6105aa88888888610dca565b90505f806105c68360400151846060015185602001518d610e9c565b91509150856105db5790935091506101c29050565b6105e6828289611091565b945094505050509550959350505050565b5f81600281900b620d89e7198161061057610610611ce9565b050292915050565b5f81600281900b620d89e88161061057610610611ce9565b8051516060820151805f5b838110156106ef57846060015160020b855f0151828151811061066057610660611c95565b602002602001015160020b1315801561069f57508460200151818151811061068a5761068a611c95565b602002602001015160020b856060015160020b125b156106e75784518051829081106106b8576106b8611c95565b60200260200101519250846020015181815181106106d8576106d8611c95565b602002602001015191506106ef565b60010161063b565b505f60026106fd8385611d5b565b6107079190611cfd565b90505f805f875f01515f8151811061072157610721611c95565b602002602001015160020b8660020b61073a9190611d80565b90505f80821361074a575f61074c565b815b90505f896080015162ffffff16821061076e57896080015162ffffff16610770565b815b90505f8760020b8b6020015160018c6107899190611cbd565b8151811061079957610799611c95565b602002602001015160020b6107ae9190611d80565b90505f8082136107be575f6107c0565b815b90505f8c60a0015162ffffff1682106107e2578c60a0015162ffffff166107e4565b815b90506107f1600385611d9f565b97506107fe600382611d9f565b9650505050505050815f0361081257600191505b805f0361081d575060015b5f8667ffffffffffffffff811115610837576108376119b8565b604051908082528060200260200182016040528015610860578160200160208202803683370190505b5090505f805b888110156109de575f805f60028d60200151858151811061088957610889611c95565b60200260200101518e5f015186815181106108a6576108a6611c95565b60200260200101516108b89190611d5b565b6108c29190611cfd565b90505f8960020b8260020b6108d79190611d80565b90505f81126108e657806108ef565b6108ef81611db2565b92508960020b8260020b1293505f84610908578861090a565b895b90505f610918826006611dcc565b85101561098d575f8261093387670de0b6b3a7640000611dcc565b61093d9190611d9f565b90505f671bc16d674ec800006109538380611de3565b61095c90611db2565b6109669190611e12565b90505f610972826114f2565b9050805f03610981575f610983565b805b9350505050610990565b505f5b808988815181106109a3576109a3611c95565b6020026020010181815250508887815181106109c1576109c1611c95565b602002602001015188019750866001019650505050505050610866565b5088610140015115610a52578015610a4d575f5b88811015610a4b57610a26838281518110610a0f57610a0f611c95565b6020026020010151670de0b6b3a7640000846116ba565b8b8281518110610a3857610a38611c95565b60209081029190910101526001016109f2565b505b610c29565b5f8867ffffffffffffffff811115610a6c57610a6c6119b8565b604051908082528060200260200182016040528015610a95578160200160208202803683370190505b5090505f805b8a811015610bd9578b6040015160020b8c602001518281518110610ac157610ac1611c95565b602002602001015160020b13610b3057610b0d8c60e00151868381518110610aeb57610aeb611c95565b6020026020010151610afd9190611dcc565b6002670de0b6b3a76400006116ba565b838281518110610b1f57610b1f611c95565b602002602001018181525050610bb0565b8b6040015160020b8c5f01518281518110610b4d57610b4d611c95565b602002602001015160020b12610b7757610b0d8c60c00151868381518110610aeb57610aeb611c95565b848181518110610b8957610b89611c95565b6020026020010151838281518110610ba357610ba3611c95565b6020026020010181815250505b828181518110610bc257610bc2611c95565b602002602001015182019150806001019050610a9b565b508015610c26575f5b8a811015610c2457610bff838281518110610a0f57610a0f611c95565b8d8281518110610c1157610c11611c95565b6020908102919091010152600101610be2565b505b50505b50505050505050505050565b8061010001511580610c4657508151155b15610c4f575050565b5f610c5e8261012001516105f7565b90505f610c6f836101200151610618565b90508160020b835f01515f81518110610c8a57610c8a611c95565b602002602001015160020b141580610cc557508060020b83602001515f81518110610cb757610cb7611c95565b602002602001015160020b14155b15610cd05750505050565b8351600103610d0657670de0b6b3a7640000845f81518110610cf457610cf4611c95565b60200260200101818152505050505050565b5f60015b8551811015610d4257858181518110610d2557610d25611c95565b602002602001015182610d389190611cd6565b9150600101610d0a565b50805f03610d70575f855f81518110610d5d57610d5d611c95565b6020026020010181815250505050505050565b60015b8551811015610db657610d91868281518110610a0f57610a0f611c95565b868281518110610da357610da3611c95565b6020908102919091010152600101610d73565b505f855f81518110610d5d57610d5d611c95565b6040805160e0810182525f60208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152600285900b8152610e0f826105f7565b60020b6080820152610e2082610618565b60020b60a0820181905260808201515f918291610e439189918991899190611757565b91509150610e528282866117b9565b60c0850181905260029190910b60208501819052608085015160a0860151610e81938b9392909189919061186f565b600290810b60608601520b6040840152509095945050505050565b6060805f600287810b9087810b9087900b5b81831215610ecd57600190930192610ec68184611e3e565b9250610eae565b8367ffffffffffffffff811115610ee657610ee66119b8565b604051908082528060200260200182016040528015610f0f578160200160208202803683370190505b5095508367ffffffffffffffff811115610f2b57610f2b6119b8565b604051908082528060200260200182016040528015610f54578160200160208202803683370190505b509450895f5b858110156110825781888281518110610f7557610f75611c95565b600292830b60209182029290920101525f90610f97908c810b9085900b611e3e565b9050627fffff811315610fd357627fffff888381518110610fba57610fba611c95565b602002602001019060020b908160020b81525050610ffb565b80888381518110610fe657610fe6611c95565b602002602001019060020b908160020b815250505b8b60020b88838151811061101157611011611c95565b602002602001015160020b131561104a578b88838151811061103557611035611c95565b602002602001019060020b908160020b815250505b5f8b60020b8460020b61105d9190611e3e565b9050627fffff811361107157809350611078565b5050611082565b5050600101610f5a565b50505050505094509492505050565b6060805f61109e846105f7565b90505f6110aa85610618565b87519091505f81900361114d576040805160018082528183019092529060208083019080368337505060408051600180825281830190925292975090506020808301908036833701905050935082855f8151811061110a5761110a611c95565b602002602001019060020b908160020b8152505081845f8151811061113157611131611c95565b602002602001019060020b908160020b815250505050506114ea565b5f195f5b828110156111ac576111978a828151811061116e5761116e611c95565b60200260200101518a838151811061118857611188611c95565b6020026020010151878761195f565b156111a4578091506111ac565b600101611151565b50805f036111c357888895509550505050506114ea565b5f19810361136a576111d6826001611cd6565b67ffffffffffffffff8111156111ee576111ee6119b8565b604051908082528060200260200182016040528015611217578160200160208202803683370190505b509550611225826001611cd6565b67ffffffffffffffff81111561123d5761123d6119b8565b604051908082528060200260200182016040528015611266578160200160208202803683370190505b50945083865f8151811061127c5761127c611c95565b602002602001019060020b908160020b8152505082855f815181106112a3576112a3611c95565b602002602001019060020b908160020b815250505f5b82811015611360578981815181106112d3576112d3611c95565b6020026020010151878260016112e99190611cd6565b815181106112f9576112f9611c95565b602002602001019060020b908160020b8152505088818151811061131f5761131f611c95565b6020026020010151868260016113359190611cd6565b8151811061134557611345611c95565b60029290920b602092830291909101909101526001016112b9565b50505050506114ea565b8167ffffffffffffffff811115611383576113836119b8565b6040519080825280602002602001820160405280156113ac578160200160208202803683370190505b5095508167ffffffffffffffff8111156113c8576113c86119b8565b6040519080825280602002602001820160405280156113f1578160200160208202803683370190505b50945083865f8151811061140757611407611c95565b602002602001019060020b908160020b8152505082855f8151811061142e5761142e611c95565b60029290920b6020928302919091019091015260015f5b838110156114e3578083146114db578a818151811061146657611466611c95565b602002602001015188838151811061148057611480611c95565b602002602001019060020b908160020b815250508981815181106114a6576114a6611c95565b60200260200101518783815181106114c0576114c0611c95565b602002602001019060020b908160020b815250508160010191505b600101611445565b5050505050505b935093915050565b5f680248ce36a70cb26b3e19821361150b57505f919050565b680755bf798b4a1bf1e582126115635760405162461bcd60e51b815260206004820152600c60248201527f4558505f4f564552464c4f5700000000000000000000000000000000000000006044820152606401610560565b6503782dace9d9604e83901b0591505f60606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093036c240c330e9fb2d9cbaf0fd5aafb1981018102606090811d6d0277594991cfc85f6e2461837cd9018202811d6d1a521255e34f6a5061b25ef1c9c319018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d6e02c72388d9f74f51a9331fed693f1419018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084016d01d3967ed30fc4f89c02bab5708119010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b5f838302815f19858709828110838203039150508084116116d9575f80fd5b805f036116eb57508290049050611750565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b5f808061176d62ffffff881660028a900b611d80565b90508460020b811261177f5780611781565b845b92505f61179762ffffff881660028b900b611e3e565b90508460020b81136117a957806117ab565b845b925050509550959350505050565b5f805f8560020b8560020b6117ce9190611d80565b905060145f6117e262ffffff871683611dcc565b905062ffffff86168160016117f78287611cd6565b6118019190611cbd565b61180b9190611d9f565b6118159190611dcc565b94508560020b8560020b1215611829578594505b611837600286900b84611d9f565b9350835f0361184557600193505b611850600285611e65565b5f0361186457611861600185611cd6565b93505b505050935093915050565b5f808360020b8860020b1215611883578397505b8260020b8860020b1315611895578297505b5f6118a3600289810b611e12565b90505f6118b48260028c900b611d80565b9050600287900b6118c58183611e12565b6118cf9190611de3565b90505f6118e060028b900b83611e3e565b90505f6118ee60028b611d9f565b905060028b900b5f6119008284611de3565b61190a9086611d80565b90508960020b81121561191e578960020b90505b9650865f61192c8385611de3565b6119369086611e3e565b90508960020b81131561194a578960020b90505b80975050505050505050965096945050505050565b5f8260020b8560020b14801561197a57508160020b8460020b145b95945050505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52604160045260245ffd5b8035600281900b81146119dd575f80fd5b919050565b5f82601f8301126119f1575f80fd5b813567ffffffffffffffff811115611a0b57611a0b6119b8565b8060051b604051601f19603f830116810181811067ffffffffffffffff82111715611a3857611a386119b8565b604052918252602081850181019290810186841115611a55575f80fd5b6020860192505b83831015611a7b57611a6d836119cc565b815260209283019201611a5c565b5095945050505050565b803562ffffff811681146119dd575f80fd5b803580151581146119dd575f80fd5b5f805f805f805f805f805f6101608c8e031215611ac1575f80fd5b8b3567ffffffffffffffff811115611ad7575f80fd5b611ae38e828f016119e2565b9b505060208c013567ffffffffffffffff811115611aff575f80fd5b611b0b8e828f016119e2565b9a5050611b1a60408d016119cc565b9850611b2860608d016119cc565b9750611b3660808d01611a85565b9650611b4460a08d01611a85565b955060c08c0135945060e08c01359350611b616101008d01611a97565b9250611b706101208d016119cc565b9150611b7f6101408d01611a97565b90509295989b509295989b9093969950565b602080825282518282018190525f918401906040840190835b81811015611bc8578351835260209384019390920191600101611baa565b509095945050505050565b5f805f805f60a08688031215611be7575f80fd5b611bf0866119cc565b9450611bfe60208701611a85565b9350611c0c60408701611a85565b9250611c1a606087016119cc565b9150611c2860808701611a97565b90509295509295909350565b5f8151808452602084019350602083015f5b82811015611c6757815160020b865260209586019590910190600101611c46565b5093949350505050565b604081525f611c836040830185611c34565b828103602084015261197a8185611c34565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b81810381811115611cd057611cd0611ca9565b92915050565b80820180821115611cd057611cd0611ca9565b634e487b7160e01b5f52601260045260245ffd5b5f8160020b8360020b80611d1357611d13611ce9565b627fffff1982145f1982141615611d2c57611d2c611ca9565b90059392505050565b5f8260020b8260020b028060020b9150808214611d5457611d54611ca9565b5092915050565b600281810b9083900b01627fffff8113627fffff1982121715611cd057611cd0611ca9565b8181035f831280158383131683831282161715611d5457611d54611ca9565b5f82611dad57611dad611ce9565b500490565b5f600160ff1b8201611dc657611dc6611ca9565b505f0390565b8082028115828204841417611cd057611cd0611ca9565b8082025f8212600160ff1b84141615611dfe57611dfe611ca9565b8181058314821517611cd057611cd0611ca9565b5f82611e2057611e20611ce9565b600160ff1b82145f1984141615611e3957611e39611ca9565b500590565b8082018281125f831280158216821582161715611e5d57611e5d611ca9565b505092915050565b5f82611e7357611e73611ce9565b50069056fe476175737369616e20646973747269627574696f6e2077697468206f7074696f6e616c2066756c6c2d72616e676520666c6f6f7220616e642077656967687420707265666572656e636573a26469706673582212204fb2563a35eab555a15ee3aa92169ac5c14069f1988f1337c26db769bf50ea8064736f6c634300081a0033

Deployed Bytecode

0x608060405234801561000f575f80fd5b5060043610610064575f3560e01c80631b7c61411161004d5780631b7c6141146100bb57806340b71404146100db57806341717726146100fc575f80fd5b80630eb9b15a146100685780631a092541146100b3575b5f80fd5b60408051808201909152600881527f476175737369616e00000000000000000000000000000000000000000000000060208201525b6040516100aa9190611983565b60405180910390f35b61009d61010b565b6100ce6100c9366004611aa6565b61012b565b6040516100aa9190611b91565b6100ee6100e9366004611bd3565b6101ad565b6040516100aa929190611c71565b604051600181526020016100aa565b60606040518060800160405280604b8152602001611e79604b9139905090565b60605f6040518061016001604052808e81526020018d81526020018c60020b81526020018b60020b81526020018a62ffffff1681526020018962ffffff16815260200188815260200187815260200186151581526020018560020b8152602001841515815250905061019c816101cc565b9d9c50505050505050505050505050565b6060806101bd8787878787610583565b915091505b9550959350505050565b8051516060908067ffffffffffffffff8111156101eb576101eb6119b8565b604051908082528060200260200182016040528015610214578160200160208202803683370190505b509150805f036102245750919050565b82610100015180156102365750600181115b156104f0575f61024a8461012001516105f7565b90505f61025b856101200151610618565b90508160020b855f01515f8151811061027657610276611c95565b602002602001015160020b1480156102b057508060020b85602001515f815181106102a3576102a3611c95565b602002602001015160020b145b156104ed575f6102c1600185611cbd565b67ffffffffffffffff8111156102d9576102d96119b8565b604051908082528060200260200182016040528015610302578160200160208202803683370190505b5090505f610311600186611cbd565b67ffffffffffffffff811115610329576103296119b8565b604051908082528060200260200182016040528015610352578160200160208202803683370190505b50905060015b8581101561040557875180518290811061037457610374611c95565b60200260200101518360018361038a9190611cbd565b8151811061039a5761039a611c95565b602002602001019060020b908160020b81525050876020015181815181106103c4576103c4611c95565b6020026020010151826001836103da9190611cbd565b815181106103ea576103ea611c95565b60029290920b60209283029190910190910152600101610358565b5081875260208701819052865f61041d600188611cbd565b67ffffffffffffffff811115610435576104356119b8565b60405190808252806020026020018201604052801561045e578160200160208202803683370190505b50905061046b8183610630565b5f885f8151811061047e5761047e611c95565b6020026020010181815250505f5b81518110156104e0578181815181106104a7576104a7611c95565b6020026020010151898260016104bd9190611cd6565b815181106104cd576104cd611c95565b602090810291909101015260010161048c565b5050505050505050919050565b50505b826101400151610569578260e001518360c0015161050e9190611cd6565b670de0b6b3a7640000146105695760405162461bcd60e51b815260206004820152601860248201527f57656967687473206d7573742073756d20746f2031653138000000000000000060448201526064015b60405180910390fd5b6105738284610630565b61057d8284610c35565b50919050565b606080836105918189611cfd565b61059b9190611d35565b96505f6105aa88888888610dca565b90505f806105c68360400151846060015185602001518d610e9c565b91509150856105db5790935091506101c29050565b6105e6828289611091565b945094505050509550959350505050565b5f81600281900b620d89e7198161061057610610611ce9565b050292915050565b5f81600281900b620d89e88161061057610610611ce9565b8051516060820151805f5b838110156106ef57846060015160020b855f0151828151811061066057610660611c95565b602002602001015160020b1315801561069f57508460200151818151811061068a5761068a611c95565b602002602001015160020b856060015160020b125b156106e75784518051829081106106b8576106b8611c95565b60200260200101519250846020015181815181106106d8576106d8611c95565b602002602001015191506106ef565b60010161063b565b505f60026106fd8385611d5b565b6107079190611cfd565b90505f805f875f01515f8151811061072157610721611c95565b602002602001015160020b8660020b61073a9190611d80565b90505f80821361074a575f61074c565b815b90505f896080015162ffffff16821061076e57896080015162ffffff16610770565b815b90505f8760020b8b6020015160018c6107899190611cbd565b8151811061079957610799611c95565b602002602001015160020b6107ae9190611d80565b90505f8082136107be575f6107c0565b815b90505f8c60a0015162ffffff1682106107e2578c60a0015162ffffff166107e4565b815b90506107f1600385611d9f565b97506107fe600382611d9f565b9650505050505050815f0361081257600191505b805f0361081d575060015b5f8667ffffffffffffffff811115610837576108376119b8565b604051908082528060200260200182016040528015610860578160200160208202803683370190505b5090505f805b888110156109de575f805f60028d60200151858151811061088957610889611c95565b60200260200101518e5f015186815181106108a6576108a6611c95565b60200260200101516108b89190611d5b565b6108c29190611cfd565b90505f8960020b8260020b6108d79190611d80565b90505f81126108e657806108ef565b6108ef81611db2565b92508960020b8260020b1293505f84610908578861090a565b895b90505f610918826006611dcc565b85101561098d575f8261093387670de0b6b3a7640000611dcc565b61093d9190611d9f565b90505f671bc16d674ec800006109538380611de3565b61095c90611db2565b6109669190611e12565b90505f610972826114f2565b9050805f03610981575f610983565b805b9350505050610990565b505f5b808988815181106109a3576109a3611c95565b6020026020010181815250508887815181106109c1576109c1611c95565b602002602001015188019750866001019650505050505050610866565b5088610140015115610a52578015610a4d575f5b88811015610a4b57610a26838281518110610a0f57610a0f611c95565b6020026020010151670de0b6b3a7640000846116ba565b8b8281518110610a3857610a38611c95565b60209081029190910101526001016109f2565b505b610c29565b5f8867ffffffffffffffff811115610a6c57610a6c6119b8565b604051908082528060200260200182016040528015610a95578160200160208202803683370190505b5090505f805b8a811015610bd9578b6040015160020b8c602001518281518110610ac157610ac1611c95565b602002602001015160020b13610b3057610b0d8c60e00151868381518110610aeb57610aeb611c95565b6020026020010151610afd9190611dcc565b6002670de0b6b3a76400006116ba565b838281518110610b1f57610b1f611c95565b602002602001018181525050610bb0565b8b6040015160020b8c5f01518281518110610b4d57610b4d611c95565b602002602001015160020b12610b7757610b0d8c60c00151868381518110610aeb57610aeb611c95565b848181518110610b8957610b89611c95565b6020026020010151838281518110610ba357610ba3611c95565b6020026020010181815250505b828181518110610bc257610bc2611c95565b602002602001015182019150806001019050610a9b565b508015610c26575f5b8a811015610c2457610bff838281518110610a0f57610a0f611c95565b8d8281518110610c1157610c11611c95565b6020908102919091010152600101610be2565b505b50505b50505050505050505050565b8061010001511580610c4657508151155b15610c4f575050565b5f610c5e8261012001516105f7565b90505f610c6f836101200151610618565b90508160020b835f01515f81518110610c8a57610c8a611c95565b602002602001015160020b141580610cc557508060020b83602001515f81518110610cb757610cb7611c95565b602002602001015160020b14155b15610cd05750505050565b8351600103610d0657670de0b6b3a7640000845f81518110610cf457610cf4611c95565b60200260200101818152505050505050565b5f60015b8551811015610d4257858181518110610d2557610d25611c95565b602002602001015182610d389190611cd6565b9150600101610d0a565b50805f03610d70575f855f81518110610d5d57610d5d611c95565b6020026020010181815250505050505050565b60015b8551811015610db657610d91868281518110610a0f57610a0f611c95565b868281518110610da357610da3611c95565b6020908102919091010152600101610d73565b505f855f81518110610d5d57610d5d611c95565b6040805160e0810182525f60208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152600285900b8152610e0f826105f7565b60020b6080820152610e2082610618565b60020b60a0820181905260808201515f918291610e439189918991899190611757565b91509150610e528282866117b9565b60c0850181905260029190910b60208501819052608085015160a0860151610e81938b9392909189919061186f565b600290810b60608601520b6040840152509095945050505050565b6060805f600287810b9087810b9087900b5b81831215610ecd57600190930192610ec68184611e3e565b9250610eae565b8367ffffffffffffffff811115610ee657610ee66119b8565b604051908082528060200260200182016040528015610f0f578160200160208202803683370190505b5095508367ffffffffffffffff811115610f2b57610f2b6119b8565b604051908082528060200260200182016040528015610f54578160200160208202803683370190505b509450895f5b858110156110825781888281518110610f7557610f75611c95565b600292830b60209182029290920101525f90610f97908c810b9085900b611e3e565b9050627fffff811315610fd357627fffff888381518110610fba57610fba611c95565b602002602001019060020b908160020b81525050610ffb565b80888381518110610fe657610fe6611c95565b602002602001019060020b908160020b815250505b8b60020b88838151811061101157611011611c95565b602002602001015160020b131561104a578b88838151811061103557611035611c95565b602002602001019060020b908160020b815250505b5f8b60020b8460020b61105d9190611e3e565b9050627fffff811361107157809350611078565b5050611082565b5050600101610f5a565b50505050505094509492505050565b6060805f61109e846105f7565b90505f6110aa85610618565b87519091505f81900361114d576040805160018082528183019092529060208083019080368337505060408051600180825281830190925292975090506020808301908036833701905050935082855f8151811061110a5761110a611c95565b602002602001019060020b908160020b8152505081845f8151811061113157611131611c95565b602002602001019060020b908160020b815250505050506114ea565b5f195f5b828110156111ac576111978a828151811061116e5761116e611c95565b60200260200101518a838151811061118857611188611c95565b6020026020010151878761195f565b156111a4578091506111ac565b600101611151565b50805f036111c357888895509550505050506114ea565b5f19810361136a576111d6826001611cd6565b67ffffffffffffffff8111156111ee576111ee6119b8565b604051908082528060200260200182016040528015611217578160200160208202803683370190505b509550611225826001611cd6565b67ffffffffffffffff81111561123d5761123d6119b8565b604051908082528060200260200182016040528015611266578160200160208202803683370190505b50945083865f8151811061127c5761127c611c95565b602002602001019060020b908160020b8152505082855f815181106112a3576112a3611c95565b602002602001019060020b908160020b815250505f5b82811015611360578981815181106112d3576112d3611c95565b6020026020010151878260016112e99190611cd6565b815181106112f9576112f9611c95565b602002602001019060020b908160020b8152505088818151811061131f5761131f611c95565b6020026020010151868260016113359190611cd6565b8151811061134557611345611c95565b60029290920b602092830291909101909101526001016112b9565b50505050506114ea565b8167ffffffffffffffff811115611383576113836119b8565b6040519080825280602002602001820160405280156113ac578160200160208202803683370190505b5095508167ffffffffffffffff8111156113c8576113c86119b8565b6040519080825280602002602001820160405280156113f1578160200160208202803683370190505b50945083865f8151811061140757611407611c95565b602002602001019060020b908160020b8152505082855f8151811061142e5761142e611c95565b60029290920b6020928302919091019091015260015f5b838110156114e3578083146114db578a818151811061146657611466611c95565b602002602001015188838151811061148057611480611c95565b602002602001019060020b908160020b815250508981815181106114a6576114a6611c95565b60200260200101518783815181106114c0576114c0611c95565b602002602001019060020b908160020b815250508160010191505b600101611445565b5050505050505b935093915050565b5f680248ce36a70cb26b3e19821361150b57505f919050565b680755bf798b4a1bf1e582126115635760405162461bcd60e51b815260206004820152600c60248201527f4558505f4f564552464c4f5700000000000000000000000000000000000000006044820152606401610560565b6503782dace9d9604e83901b0591505f60606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093036c240c330e9fb2d9cbaf0fd5aafb1981018102606090811d6d0277594991cfc85f6e2461837cd9018202811d6d1a521255e34f6a5061b25ef1c9c319018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d6e02c72388d9f74f51a9331fed693f1419018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084016d01d3967ed30fc4f89c02bab5708119010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b5f838302815f19858709828110838203039150508084116116d9575f80fd5b805f036116eb57508290049050611750565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b5f808061176d62ffffff881660028a900b611d80565b90508460020b811261177f5780611781565b845b92505f61179762ffffff881660028b900b611e3e565b90508460020b81136117a957806117ab565b845b925050509550959350505050565b5f805f8560020b8560020b6117ce9190611d80565b905060145f6117e262ffffff871683611dcc565b905062ffffff86168160016117f78287611cd6565b6118019190611cbd565b61180b9190611d9f565b6118159190611dcc565b94508560020b8560020b1215611829578594505b611837600286900b84611d9f565b9350835f0361184557600193505b611850600285611e65565b5f0361186457611861600185611cd6565b93505b505050935093915050565b5f808360020b8860020b1215611883578397505b8260020b8860020b1315611895578297505b5f6118a3600289810b611e12565b90505f6118b48260028c900b611d80565b9050600287900b6118c58183611e12565b6118cf9190611de3565b90505f6118e060028b900b83611e3e565b90505f6118ee60028b611d9f565b905060028b900b5f6119008284611de3565b61190a9086611d80565b90508960020b81121561191e578960020b90505b9650865f61192c8385611de3565b6119369086611e3e565b90508960020b81131561194a578960020b90505b80975050505050505050965096945050505050565b5f8260020b8560020b14801561197a57508160020b8460020b145b95945050505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52604160045260245ffd5b8035600281900b81146119dd575f80fd5b919050565b5f82601f8301126119f1575f80fd5b813567ffffffffffffffff811115611a0b57611a0b6119b8565b8060051b604051601f19603f830116810181811067ffffffffffffffff82111715611a3857611a386119b8565b604052918252602081850181019290810186841115611a55575f80fd5b6020860192505b83831015611a7b57611a6d836119cc565b815260209283019201611a5c565b5095945050505050565b803562ffffff811681146119dd575f80fd5b803580151581146119dd575f80fd5b5f805f805f805f805f805f6101608c8e031215611ac1575f80fd5b8b3567ffffffffffffffff811115611ad7575f80fd5b611ae38e828f016119e2565b9b505060208c013567ffffffffffffffff811115611aff575f80fd5b611b0b8e828f016119e2565b9a5050611b1a60408d016119cc565b9850611b2860608d016119cc565b9750611b3660808d01611a85565b9650611b4460a08d01611a85565b955060c08c0135945060e08c01359350611b616101008d01611a97565b9250611b706101208d016119cc565b9150611b7f6101408d01611a97565b90509295989b509295989b9093969950565b602080825282518282018190525f918401906040840190835b81811015611bc8578351835260209384019390920191600101611baa565b509095945050505050565b5f805f805f60a08688031215611be7575f80fd5b611bf0866119cc565b9450611bfe60208701611a85565b9350611c0c60408701611a85565b9250611c1a606087016119cc565b9150611c2860808701611a97565b90509295509295909350565b5f8151808452602084019350602083015f5b82811015611c6757815160020b865260209586019590910190600101611c46565b5093949350505050565b604081525f611c836040830185611c34565b828103602084015261197a8185611c34565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b81810381811115611cd057611cd0611ca9565b92915050565b80820180821115611cd057611cd0611ca9565b634e487b7160e01b5f52601260045260245ffd5b5f8160020b8360020b80611d1357611d13611ce9565b627fffff1982145f1982141615611d2c57611d2c611ca9565b90059392505050565b5f8260020b8260020b028060020b9150808214611d5457611d54611ca9565b5092915050565b600281810b9083900b01627fffff8113627fffff1982121715611cd057611cd0611ca9565b8181035f831280158383131683831282161715611d5457611d54611ca9565b5f82611dad57611dad611ce9565b500490565b5f600160ff1b8201611dc657611dc6611ca9565b505f0390565b8082028115828204841417611cd057611cd0611ca9565b8082025f8212600160ff1b84141615611dfe57611dfe611ca9565b8181058314821517611cd057611cd0611ca9565b5f82611e2057611e20611ce9565b600160ff1b82145f1984141615611e3957611e39611ca9565b500590565b8082018281125f831280158216821582161715611e5d57611e5d611ca9565b505092915050565b5f82611e7357611e73611ce9565b50069056fe476175737369616e20646973747269627574696f6e2077697468206f7074696f6e616c2066756c6c2d72616e676520666c6f6f7220616e642077656967687420707265666572656e636573a26469706673582212204fb2563a35eab555a15ee3aa92169ac5c14069f1988f1337c26db769bf50ea8064736f6c634300081a0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.