Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/strategies/ExponentialStrategy.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;
import "./ILiquidityStrategy.sol";
import "./LiquidityDistributionLibrary.sol";
import {TickMath} from "v4-core/libraries/TickMath.sol";
import {wadExp} from "solmate/src/utils/SignedWadMath.sol";
import {FullMath} from "v4-core/libraries/FullMath.sol";
/**
* @title ExponentialStrategy
* @notice Unified Exponential distribution strategy supporting all options
* @dev Supports standard, carpeted, weighted, and weighted+carpeted variants
*/
contract ExponentialStrategy is ILiquidityStrategy {
uint256 public constant CARPET_WEIGHT = 0.00005e18; // 0.005% carpet weight
struct DensityParams {
int24[] lowerTicks;
int24[] upperTicks;
int24 currentTick;
int24 centerTick;
uint24 ticksLeft;
uint24 ticksRight;
uint256 weight0;
uint256 weight1;
bool useCarpet;
int24 tickSpacing;
bool weightsAreProportional;
}
struct CarpetInfo {
bool hasLeftCarpet;
bool hasRightCarpet;
uint256 startIdx;
uint256 endIdx;
uint256 numRanges;
}
/**
* @notice Generate ranges with optional carpet positions
* @dev Allows explicit control over carpet position generation
*/
function generateRanges(
int24 centerTick,
uint24 ticksLeft,
uint24 ticksRight,
int24 tickSpacing,
bool useCarpet
) external pure override returns (
int24[] memory lowerTicks,
int24[] memory upperTicks
) {
return _generateRanges(centerTick, ticksLeft, ticksRight, tickSpacing, useCarpet);
}
function _generateRanges(
int24 centerTick,
uint24 ticksLeft,
uint24 ticksRight,
int24 tickSpacing,
bool useCarpet
) internal pure returns (
int24[] memory lowerTicks,
int24[] memory upperTicks
) {
// Align center tick to tick spacing
centerTick = (centerTick / tickSpacing) * tickSpacing;
// Calculate and clamp bounds
int24 leftBound;
int24 rightBound;
{
// Safe calculation for leftBound
int256 tempLeft = int256(centerTick) - int256(uint256(ticksLeft));
if (tempLeft < int256(type(int24).min)) {
leftBound = type(int24).min;
} else {
leftBound = int24(tempLeft);
}
// Safe calculation for rightBound
int256 tempRight = int256(centerTick) + int256(uint256(ticksRight));
if (tempRight > int256(type(int24).max)) {
rightBound = type(int24).max;
} else {
rightBound = int24(tempRight);
}
// Clamp to Uniswap v4's usable tick bounds BEFORE calculating width
int24 minUsable = TickMath.minUsableTick(tickSpacing);
int24 maxUsable = TickMath.maxUsableTick(tickSpacing);
if (leftBound < minUsable) leftBound = minUsable;
if (rightBound > maxUsable) rightBound = maxUsable;
}
// Calculate width from actual span
int24 width;
{
uint256 actualSpan = uint256(int256(rightBound) - int256(leftBound));
uint256 divisor = 20 * uint24(tickSpacing);
width = int24(uint24(((actualSpan + divisor - 1) / divisor) * uint24(tickSpacing)));
if (width < tickSpacing) width = tickSpacing;
}
// Align bounds to width
leftBound = (leftBound / width) * width;
rightBound = (rightBound / width) * width;
// Ensure bounds stay within usable range after alignment
{
int24 minUsable = TickMath.minUsableTick(tickSpacing);
int24 maxUsable = TickMath.maxUsableTick(tickSpacing);
if (leftBound < minUsable) leftBound = minUsable;
if (rightBound > maxUsable) rightBound = maxUsable;
}
if (useCarpet) {
return _generateRangesWithCarpet(leftBound, rightBound, width, tickSpacing);
} else {
return _generateStandardRanges(leftBound, rightBound, width);
}
}
function _generateStandardRanges(
int24 leftBound,
int24 rightBound,
int24 width
) private pure returns (
int24[] memory lowerTicks,
int24[] memory upperTicks
) {
// Count how many ranges we'll create
uint256 numRanges;
int256 currentInt = int256(leftBound);
int256 rightBoundInt = int256(rightBound);
int256 widthInt = int256(uint256(int256(width)));
while (currentInt < rightBoundInt) {
unchecked {
++numRanges;
}
currentInt += widthInt;
}
// Allocate arrays
lowerTicks = new int24[](numRanges);
upperTicks = new int24[](numRanges);
// Generate non-overlapping ranges
int24 current = leftBound;
for (uint256 i = 0; i < numRanges; ) {
lowerTicks[i] = current;
// Safe addition to avoid overflow
int256 nextUpper = int256(current) + int256(uint256(int256(width)));
if (nextUpper > int256(type(int24).max)) {
upperTicks[i] = type(int24).max;
} else {
upperTicks[i] = int24(nextUpper);
}
// Ensure we don't exceed right bound
if (upperTicks[i] > rightBound) {
upperTicks[i] = rightBound;
}
// Safe addition for loop increment
int256 nextCurrent = int256(current) + int256(uint256(int256(width)));
if (nextCurrent <= int256(type(int24).max)) {
current = int24(nextCurrent);
} else {
break; // Exit loop if we would overflow
}
unchecked { ++i; }
}
}
function _generateRangesWithCarpet(
int24 leftBound,
int24 rightBound,
int24 width,
int24 tickSpacing
) private pure returns (
int24[] memory lowerTicks,
int24[] memory upperTicks
) {
// Get base ranges first
(int24[] memory baseLowers, int24[] memory baseUppers) = _generateStandardRanges(leftBound, rightBound, width);
// Get usable tick bounds
int24 minUsable = TickMath.minUsableTick(tickSpacing);
int24 maxUsable = TickMath.maxUsableTick(tickSpacing);
// Check if we need carpet ranges
bool hasLeftCarpet = baseLowers[0] > minUsable;
bool hasRightCarpet = baseUppers[baseUppers.length - 1] < maxUsable;
// Calculate total number of ranges
uint256 numCarpetRanges;
if (hasLeftCarpet) {
unchecked {
++numCarpetRanges;
}
}
if (hasRightCarpet) {
unchecked {
++numCarpetRanges;
}
}
uint256 totalRanges = baseLowers.length + numCarpetRanges;
lowerTicks = new int24[](totalRanges);
upperTicks = new int24[](totalRanges);
uint256 idx;
// Add left carpet if needed
if (hasLeftCarpet) {
lowerTicks[idx] = minUsable;
upperTicks[idx] = baseLowers[0];
unchecked {
++idx;
}
}
// Add base ranges
uint256 baseLength = baseLowers.length;
for (uint256 i = 0; i < baseLength; ) {
lowerTicks[idx] = baseLowers[i];
upperTicks[idx] = baseUppers[i];
unchecked {
++idx;
++i;
}
}
// Add right carpet if needed
if (hasRightCarpet) {
lowerTicks[idx] = baseUppers[baseUppers.length - 1];
upperTicks[idx] = maxUsable;
}
}
/**
* @notice Calculate Exponential density with all options
*/
function calculateDensities(
int24[] memory lowerTicks,
int24[] memory upperTicks,
int24 currentTick,
int24 centerTick,
uint24 ticksLeft,
uint24 ticksRight,
uint256 weight0,
uint256 weight1,
bool useCarpet,
int24 tickSpacing,
bool weightsAreProportional
) public pure override returns (uint256[] memory weights) {
DensityParams memory params = DensityParams({
lowerTicks: lowerTicks,
upperTicks: upperTicks,
currentTick: currentTick,
centerTick: centerTick,
ticksLeft: ticksLeft,
ticksRight: ticksRight,
weight0: weight0,
weight1: weight1,
useCarpet: useCarpet,
tickSpacing: tickSpacing,
weightsAreProportional: weightsAreProportional
});
return _calculateDensitiesInternal(params);
}
function _calculateDensitiesInternal(
DensityParams memory params
) private pure returns (uint256[] memory weights) {
uint256 numRanges = params.lowerTicks.length;
weights = new uint256[](numRanges);
if (numRanges == 0) return weights;
// Validate weights sum to 1e18 (skip for proportional weights)
if (!params.weightsAreProportional) {
require(params.weight0 + params.weight1 == 1e18, "Weights must sum to 1e18");
}
if (params.useCarpet) {
_processWeightsWithCarpet(weights, params);
} else {
_processWeightsNoCarpet(weights, params);
}
return weights;
}
function _processWeightsNoCarpet(
uint256[] memory weights,
DensityParams memory params
) private pure {
uint256 numRanges = params.lowerTicks.length;
// Calculate lambda parameters for exponential decay
uint256 lambdaLeft = uint256(params.ticksLeft) / 3;
uint256 lambdaRight = uint256(params.ticksRight) / 3;
if (lambdaLeft == 0) lambdaLeft = 1;
if (lambdaRight == 0) lambdaRight = 1;
// Calculate base exponential weights
uint256[] memory baseWeights = new uint256[](numRanges);
uint256 totalBaseWeight;
for (uint256 i = 0; i < numRanges; ) {
// Calculate midpoint of range (safe to prevent overflow)
int256 midpointInt = (int256(params.lowerTicks[i]) + int256(params.upperTicks[i])) / 2;
int24 midpoint = int24(midpointInt);
// Calculate distance from center
int256 distance = int256(midpoint) - int256(params.centerTick);
uint256 absDistance = distance < 0 ? uint256(-distance) : uint256(distance);
// Use appropriate lambda based on side
uint256 lambda = distance < 0 ? lambdaLeft : lambdaRight;
// Apply true exponential formula: exp(-absDistance/lambda)
// wadExp expects input in WAD (1e18) format
// We need to compute exp(-absDistance/lambda) = exp(-(absDistance * 1e18) / (lambda * 1e18))
uint256 weight;
if (absDistance < lambda * 10) { // Cutoff at 10*lambda for negligible weights
// Calculate -absDistance/lambda in WAD format
int256 exponent = -int256((absDistance * 1e18) / lambda);
// wadExp returns exp(x) where x is in WAD format
int256 expResult = wadExp(exponent);
// Convert back to uint256, clamping negative values to 0
weight = expResult > 0 ? uint256(expResult) : 0;
} else {
weight = 0; // Negligible weight far from center
}
baseWeights[i] = weight;
unchecked {
totalBaseWeight += weight;
++i;
}
}
// Apply weight preferences
if (params.weightsAreProportional) {
// Proportional weights: use base distribution (no filtering)
if (totalBaseWeight != 0) {
for (uint256 i = 0; i < numRanges; ) {
weights[i] = FullMath.mulDiv(baseWeights[i], LiquidityDistributionLibrary.WAD, totalBaseWeight);
unchecked { ++i; }
}
}
} else {
// Explicit preferences: apply weight-based filtering
uint256[] memory adjustedWeights = new uint256[](numRanges);
uint256 totalAdjustedWeight;
for (uint256 i = 0; i < numRanges; ) {
if (params.upperTicks[i] <= params.currentTick) {
adjustedWeights[i] = FullMath.mulDiv(baseWeights[i] * params.weight1, 2, 1e18);
} else if (params.lowerTicks[i] >= params.currentTick) {
adjustedWeights[i] = FullMath.mulDiv(baseWeights[i] * params.weight0, 2, 1e18);
} else {
adjustedWeights[i] = baseWeights[i];
}
unchecked {
totalAdjustedWeight += adjustedWeights[i];
++i;
}
}
// Normalize to sum to 1e18
if (totalAdjustedWeight != 0) {
for (uint256 i = 0; i < numRanges; ) {
weights[i] = FullMath.mulDiv(adjustedWeights[i], LiquidityDistributionLibrary.WAD, totalAdjustedWeight);
unchecked { ++i; }
}
}
}
}
function _processWeightsWithCarpet(
uint256[] memory weights,
DensityParams memory params
) private pure {
_processWeightsWithCarpetPhase1(weights, params);
}
function _processWeightsWithCarpetPhase1(
uint256[] memory weights,
DensityParams memory params
) private pure {
uint256 numRanges = params.lowerTicks.length;
// Use the tick spacing from params instead of inferring
int24 tickSpacing = params.tickSpacing;
(bool hasLeftCarpet, bool hasRightCarpet, uint256 startIdx, uint256 endIdx) =
_getCarpetInfo(params.lowerTicks, params.upperTicks, numRanges, tickSpacing);
// Calculate lambda parameters
uint256 lambdaLeft = uint256(params.ticksLeft) / 3;
uint256 lambdaRight = uint256(params.ticksRight) / 3;
if (lambdaLeft == 0) lambdaLeft = 1;
if (lambdaRight == 0) lambdaRight = 1;
// Calculate base and adjusted weights
(uint256[] memory adjustedWeights, uint256 totalAdjustedWeight) = _calculateExponentialWeights(
params,
startIdx,
endIdx,
lambdaLeft,
lambdaRight
);
// Store carpet info in a struct to reduce parameters
CarpetInfo memory carpetInfo = CarpetInfo({
hasLeftCarpet: hasLeftCarpet,
hasRightCarpet: hasRightCarpet,
startIdx: startIdx,
endIdx: endIdx,
numRanges: numRanges
});
// Finalize carpet weights
_finalizeCarpetWeights(
weights,
adjustedWeights,
totalAdjustedWeight,
carpetInfo
);
}
function _getCarpetInfo(
int24[] memory lowerTicks,
int24[] memory upperTicks,
uint256 numRanges,
int24 tickSpacing
) private pure returns (
bool hasLeftCarpet,
bool hasRightCarpet,
uint256 startIdx,
uint256 endIdx
) {
int24 minUsable = TickMath.minUsableTick(tickSpacing);
int24 maxUsable = TickMath.maxUsableTick(tickSpacing);
hasLeftCarpet = lowerTicks[0] == minUsable;
hasRightCarpet = upperTicks[numRanges - 1] == maxUsable;
startIdx = hasLeftCarpet ? 1 : 0;
endIdx = hasRightCarpet ? numRanges - 1 : numRanges;
}
function _calculateExponentialWeights(
DensityParams memory params,
uint256 startIdx,
uint256 endIdx,
uint256 lambdaLeft,
uint256 lambdaRight
) private pure returns (uint256[] memory adjustedWeights, uint256 totalAdjustedWeight) {
uint256 numRanges = params.lowerTicks.length;
uint256[] memory baseWeights = new uint256[](numRanges);
uint256 totalBaseWeight;
// Calculate base exponential weights for main ranges
for (uint256 i = startIdx; i < endIdx; ) {
int256 midpointInt = (int256(params.lowerTicks[i]) + int256(params.upperTicks[i])) / 2;
int24 midpoint = int24(midpointInt);
int256 distance = int256(midpoint) - int256(params.centerTick);
uint256 absDistance = distance < 0 ? uint256(-distance) : uint256(distance);
uint256 lambda = distance < 0 ? lambdaLeft : lambdaRight;
// Apply true exponential formula: exp(-absDistance/lambda)
uint256 weight;
if (absDistance < lambda * 10) { // Cutoff at 10*lambda for negligible weights
// Calculate -absDistance/lambda in WAD format
int256 exponent = -int256((absDistance * 1e18) / lambda);
// wadExp returns exp(x) where x is in WAD format
int256 expResult = wadExp(exponent);
// Convert back to uint256, clamping negative values to 0
weight = expResult > 0 ? uint256(expResult) : 0;
} else {
weight = 0; // Negligible weight far from center
}
baseWeights[i] = weight;
unchecked {
totalBaseWeight += weight;
++i;
}
}
// Apply weight preferences to main ranges
adjustedWeights = new uint256[](numRanges);
if (params.weightsAreProportional) {
// Proportional weights: use base distribution (no filtering)
for (uint256 i = startIdx; i < endIdx; ) {
adjustedWeights[i] = baseWeights[i];
unchecked {
totalAdjustedWeight += adjustedWeights[i];
++i;
}
}
} else {
// Explicit preferences: apply weight-based filtering
for (uint256 i = startIdx; i < endIdx; ) {
if (params.upperTicks[i] <= params.currentTick) {
adjustedWeights[i] = FullMath.mulDiv(baseWeights[i] * params.weight1, 2, 1e18);
} else if (params.lowerTicks[i] >= params.currentTick) {
adjustedWeights[i] = FullMath.mulDiv(baseWeights[i] * params.weight0, 2, 1e18);
} else {
adjustedWeights[i] = baseWeights[i];
}
unchecked {
totalAdjustedWeight += adjustedWeights[i];
++i;
}
}
}
}
function _finalizeCarpetWeights(
uint256[] memory weights,
uint256[] memory adjustedWeights,
uint256 totalAdjustedWeight,
CarpetInfo memory carpetInfo
) private pure {
uint256 numCarpetRanges;
if (carpetInfo.hasLeftCarpet) {
unchecked {
++numCarpetRanges;
}
}
if (carpetInfo.hasRightCarpet) {
unchecked {
++numCarpetRanges;
}
}
// Only subtract CARPET_WEIGHT if we actually have carpet ranges
uint256 carpetWeightPerRange = numCarpetRanges != 0 ? CARPET_WEIGHT / numCarpetRanges : 0;
uint256 remainingWeight = numCarpetRanges != 0 ?
LiquidityDistributionLibrary.WAD - CARPET_WEIGHT :
LiquidityDistributionLibrary.WAD;
if (carpetInfo.hasLeftCarpet) {
weights[0] = carpetWeightPerRange;
}
if (carpetInfo.hasRightCarpet) {
weights[carpetInfo.numRanges - 1] = carpetWeightPerRange;
}
// Normalize main range weights
if (totalAdjustedWeight != 0) {
for (uint256 i = carpetInfo.startIdx; i < carpetInfo.endIdx; ) {
weights[i] = FullMath.mulDiv(adjustedWeights[i], remainingWeight, totalAdjustedWeight);
unchecked { ++i; }
}
}
}
/**
* @notice This strategy supports weighted distribution
*/
function supportsWeights() external pure override returns (bool) {
return true;
}
/**
* @notice Get strategy type identifier
*/
function getStrategyType() external pure override returns (string memory) {
return "Exponential";
}
/**
* @notice Get human-readable description
*/
function getDescription() external pure override returns (string memory) {
return "Exponential distribution with optional carpet and weight preferences";
}
}"
},
"src/strategies/ILiquidityStrategy.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;
/**
* @title ILiquidityStrategy
* @notice Interface for liquidity distribution strategies matching Python shapes
* @dev Each strategy implements a different distribution pattern (uniform, triangle, gaussian, etc.)
*/
interface ILiquidityStrategy {
/**
* @notice Generate tick ranges with optional carpet positions
* @param centerTick The center tick for the strategy
* @param ticksLeft Number of ticks to the left of center for the distribution
* @param ticksRight Number of ticks to the right of center for the distribution
* @param tickSpacing The tick spacing of the pool
* @param useCarpet Whether to add carpet positions at extreme ticks for TWAP support
* @return lowerTicks Array of lower ticks for each position
* @return upperTicks Array of upper ticks for each position
*/
function generateRanges(
int24 centerTick,
uint24 ticksLeft,
uint24 ticksRight,
int24 tickSpacing,
bool useCarpet
) external view returns (
int24[] memory lowerTicks,
int24[] memory upperTicks
);
/**
* @notice Get the strategy type identifier
* @return strategyType String identifier for the strategy (e.g., "uniform", "triangle", "gaussian")
*/
function getStrategyType() external view returns (string memory strategyType);
/**
* @notice Get a description of the strategy
* @return description Human-readable description of the distribution pattern
*/
function getDescription() external view returns (string memory description);
/**
* @notice Check if this strategy supports weighted distribution
* @return supported True if the strategy implements calculateDensitiesWithWeights
*/
function supportsWeights() external pure returns (bool supported);
/**
* @notice Calculate density weights with token weights and carpet options
* @dev Comprehensive function that supports both token weights and carpet liquidity
* @param lowerTicks Array of lower ticks for each position
* @param upperTicks Array of upper ticks for each position
* @param currentTick Current tick of the pool
* @param centerTick Center tick for the distribution
* @param ticksLeft Number of ticks to the left of center for the shape
* @param ticksRight Number of ticks to the right of center for the shape
* @param weight0 Weight preference for token0 (scaled to 1e18, e.g., 0.8e18 for 80%)
* @param weight1 Weight preference for token1 (scaled to 1e18, e.g., 0.2e18 for 20%)
* @param useCarpet Whether to add carpet liquidity at extremes (0.01% each)
* @param tickSpacing The tick spacing of the pool
* @param weightsAreProportional True if weights were auto-calculated from available tokens (should not filter ranges)
* @return weights Array of weights for each position (scaled to 1e18, sum = 1e18)
*/
function calculateDensities(
int24[] memory lowerTicks,
int24[] memory upperTicks,
int24 currentTick,
int24 centerTick,
uint24 ticksLeft,
uint24 ticksRight,
uint256 weight0,
uint256 weight1,
bool useCarpet,
int24 tickSpacing,
bool weightsAreProportional
) external view returns (uint256[] memory weights);
}"
},
"src/strategies/LiquidityDistributionLibrary.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;
import {wadExp} from "solmate/src/utils/SignedWadMath.sol";
/**
* @title LiquidityDistributionLibrary
* @notice Library for mathematical functions used in liquidity distribution strategies
* @dev Implements approximations for exp, gaussian, and other mathematical functions
*/
library LiquidityDistributionLibrary {
uint256 constant WAD = 1e18;
uint256 constant HALF_WAD = 5e17;
/**
* @notice Calculate the absolute difference between two int24 values
* @param a First value
* @param b Second value
* @return The absolute difference as uint256
*/
function absDiff(int24 a, int24 b) internal pure returns (uint256) {
return a > b ? uint256(int256(a - b)) : uint256(int256(b - a));
}
/**
* @notice Calculate the center tick of a position
* @param lowerTick Lower tick of the position
* @param upperTick Upper tick of the position
* @return Center tick of the position
*/
function centerTick(int24 lowerTick, int24 upperTick) internal pure returns (int24) {
return (lowerTick + upperTick) / 2;
}
/**
* @notice Approximate exponential function using Taylor series
* @dev exp(x) ≈ 1 + x + x²/2 + x³/6 + x⁴/24 for small x
* @param x Input scaled by WAD (negative values for decay)
* @return Approximation of exp(x) scaled by WAD
*/
function exp(int256 x) internal pure returns (uint256) {
// Use solmate's wadExp for precise exponential calculation
int256 result = wadExp(x);
// Convert to uint256, ensuring non-negative
return result > 0 ? uint256(result) : 0;
}
/**
* @notice Calculate gaussian-like density
* @dev Uses exp(-(x²/2σ²)) approximation
* @param distance Distance from center (absolute value)
* @param sigma Standard deviation scaled by WAD
* @return Gaussian density value scaled by WAD
*/
function gaussian(uint256 distance, uint256 sigma) internal pure returns (uint256) {
if (sigma == 0) return distance == 0 ? WAD : 0;
// Calculate -(distance²)/(2σ²)
// Scale down to prevent overflow
uint256 scaledDist = (distance * WAD) / sigma;
// If distance is too large, return minimal value
if (scaledDist > 3 * WAD) return 1; // Beyond 3 sigma
// Calculate exp(-(scaledDist²)/2)
uint256 exponent = (scaledDist * scaledDist) / (2 * WAD);
return exp(-int256(exponent));
}
/**
* @notice Calculate triangle distribution density
* @param distance Distance from center
* @param maxDistance Maximum distance (triangle base)
* @return Triangle density value scaled by WAD
*/
function triangle(uint256 distance, uint256 maxDistance) internal pure returns (uint256) {
if (maxDistance == 0 || distance >= maxDistance) return 0;
// Linear decay from center: (1 - distance/maxDistance)
return WAD - (distance * WAD) / maxDistance;
}
/**
* @notice Calculate exponential distribution density
* @param distance Distance from center
* @param lambda Decay parameter scaled by WAD
* @return Exponential density value scaled by WAD
*/
function exponential(uint256 distance, uint256 lambda) internal pure returns (uint256) {
if (lambda == 0) return distance == 0 ? WAD : 0;
// Calculate exp(-distance/lambda)
int256 exponent = -int256((distance * WAD) / lambda);
return exp(exponent);
}
/**
* @notice Normalize an array of weights to sum to WAD
* @param weights Array of weights to normalize
* @return normalized Array of normalized weights
*/
function normalize(uint256[] memory weights) internal pure returns (uint256[] memory normalized) {
uint256 length = weights.length;
normalized = new uint256[](length);
// Calculate sum
uint256 sum;
for (uint256 i = 0; i < length; ) {
unchecked {
sum += weights[i];
++i;
}
}
// If sum is zero, distribute equally
if (sum == 0) {
uint256 equalWeight = WAD / length;
uint256 remainder;
unchecked {
remainder = WAD - (equalWeight * length);
}
for (uint256 i = 0; i < length; ) {
normalized[i] = equalWeight;
if (i == length - 1) {
unchecked {
normalized[i] += remainder;
}
}
unchecked { ++i; }
}
return normalized;
}
// Normalize to sum = WAD
uint256 normalizedSum;
for (uint256 i = 0; i < length; ) {
if (i == length - 1) {
// Last element gets the remainder to ensure exact sum
normalized[i] = WAD - normalizedSum;
} else {
normalized[i] = (weights[i] * WAD) / sum;
unchecked {
normalizedSum += normalized[i];
}
}
unchecked { ++i; }
}
return normalized;
}
/**
* @notice Calculate camel distribution (double-peaked)
* @param distance Distance from center
* @param maxDistance Maximum distance
* @param peakOffset Offset of peaks from center (as fraction of maxDistance)
* @return Camel density value scaled by WAD
*/
function camel(uint256 distance, uint256 maxDistance, uint256 peakOffset) internal pure returns (uint256) {
if (maxDistance == 0) return 0;
// Create two peaks at ±peakOffset from center
uint256 leftPeak = (maxDistance * peakOffset) / WAD;
uint256 rightPeak = leftPeak;
// Calculate distance to nearest peak
uint256 distToLeft = distance > leftPeak ? distance - leftPeak : leftPeak - distance;
uint256 distToRight = distance > rightPeak ? distance - rightPeak : rightPeak - distance;
uint256 minDist = distToLeft < distToRight ? distToLeft : distToRight;
// Use gaussian-like decay from nearest peak
uint256 sigma = maxDistance / 3;
uint256 density = gaussian(minDist, sigma);
// Add base level to connect the peaks
return density + (WAD / 10); // Add 10% base level
}
}"
},
"lib/v4-periphery/lib/v4-core/src/libraries/TickMath.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {BitMath} from "./BitMath.sol";
import {CustomRevert} from "./CustomRevert.sol";
/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
using CustomRevert for bytes4;
/// @notice Thrown when the tick passed to #getSqrtPriceAtTick is not between MIN_TICK and MAX_TICK
error InvalidTick(int24 tick);
/// @notice Thrown when the price passed to #getTickAtSqrtPrice does not correspond to a price between MIN_TICK and MAX_TICK
error InvalidSqrtPrice(uint160 sqrtPriceX96);
/// @dev The minimum tick that may be passed to #getSqrtPriceAtTick computed from log base 1.0001 of 2**-128
/// @dev If ever MIN_TICK and MAX_TICK are not centered around 0, the absTick logic in getSqrtPriceAtTick cannot be used
int24 internal constant MIN_TICK = -887272;
/// @dev The maximum tick that may be passed to #getSqrtPriceAtTick computed from log base 1.0001 of 2**128
/// @dev If ever MIN_TICK and MAX_TICK are not centered around 0, the absTick logic in getSqrtPriceAtTick cannot be used
int24 internal constant MAX_TICK = 887272;
/// @dev The minimum tick spacing value drawn from the range of type int16 that is greater than 0, i.e. min from the range [1, 32767]
int24 internal constant MIN_TICK_SPACING = 1;
/// @dev The maximum tick spacing value drawn from the range of type int16, i.e. max from the range [1, 32767]
int24 internal constant MAX_TICK_SPACING = type(int16).max;
/// @dev The minimum value that can be returned from #getSqrtPriceAtTick. Equivalent to getSqrtPriceAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_PRICE = 4295128739;
/// @dev The maximum value that can be returned from #getSqrtPriceAtTick. Equivalent to getSqrtPriceAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_PRICE = 1461446703485210103287273052203988822378723970342;
/// @dev A threshold used for optimized bounds check, equals `MAX_SQRT_PRICE - MIN_SQRT_PRICE - 1`
uint160 internal constant MAX_SQRT_PRICE_MINUS_MIN_SQRT_PRICE_MINUS_ONE =
1461446703485210103287273052203988822378723970342 - 4295128739 - 1;
/// @notice Given a tickSpacing, compute the maximum usable tick
function maxUsableTick(int24 tickSpacing) internal pure returns (int24) {
unchecked {
return (MAX_TICK / tickSpacing) * tickSpacing;
}
}
/// @notice Given a tickSpacing, compute the minimum usable tick
function minUsableTick(int24 tickSpacing) internal pure returns (int24) {
unchecked {
return (MIN_TICK / tickSpacing) * tickSpacing;
}
}
/// @notice Calculates sqrt(1.0001^tick) * 2^96
/// @dev Throws if |tick| > max tick
/// @param tick The input tick for the above formula
/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the price of the two assets (currency1/currency0)
/// at the given tick
function getSqrtPriceAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
unchecked {
uint256 absTick;
assembly ("memory-safe") {
tick := signextend(2, tick)
// mask = 0 if tick >= 0 else -1 (all 1s)
let mask := sar(255, tick)
// if tick >= 0, |tick| = tick = 0 ^ tick
// if tick < 0, |tick| = ~~|tick| = ~(-|tick| - 1) = ~(tick - 1) = (-1) ^ (tick - 1)
// either way, |tick| = mask ^ (tick + mask)
absTick := xor(mask, add(mask, tick))
}
if (absTick > uint256(int256(MAX_TICK))) InvalidTick.selector.revertWith(tick);
// The tick is decomposed into bits, and for each bit with index i that is set, the product of 1/sqrt(1.0001^(2^i))
// is calculated (using Q128.128). The constants used for this calculation are rounded to the nearest integer
// Equivalent to:
// price = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
// or price = int(2**128 / sqrt(1.0001)) if (absTick & 0x1) else 1 << 128
uint256 price;
assembly ("memory-safe") {
price := xor(shl(128, 1), mul(xor(shl(128, 1), 0xfffcb933bd6fad37aa2d162d1a594001), and(absTick, 0x1)))
}
if (absTick & 0x2 != 0) price = (price * 0xfff97272373d413259a46990580e213a) >> 128;
if (absTick & 0x4 != 0) price = (price * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
if (absTick & 0x8 != 0) price = (price * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
if (absTick & 0x10 != 0) price = (price * 0xffcb9843d60f6159c9db58835c926644) >> 128;
if (absTick & 0x20 != 0) price = (price * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
if (absTick & 0x40 != 0) price = (price * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
if (absTick & 0x80 != 0) price = (price * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
if (absTick & 0x100 != 0) price = (price * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
if (absTick & 0x200 != 0) price = (price * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
if (absTick & 0x400 != 0) price = (price * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
if (absTick & 0x800 != 0) price = (price * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
if (absTick & 0x1000 != 0) price = (price * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
if (absTick & 0x2000 != 0) price = (price * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
if (absTick & 0x4000 != 0) price = (price * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
if (absTick & 0x8000 != 0) price = (price * 0x31be135f97d08fd981231505542fcfa6) >> 128;
if (absTick & 0x10000 != 0) price = (price * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
if (absTick & 0x20000 != 0) price = (price * 0x5d6af8dedb81196699c329225ee604) >> 128;
if (absTick & 0x40000 != 0) price = (price * 0x2216e584f5fa1ea926041bedfe98) >> 128;
if (absTick & 0x80000 != 0) price = (price * 0x48a170391f7dc42444e8fa2) >> 128;
assembly ("memory-safe") {
// if (tick > 0) price = type(uint256).max / price;
if sgt(tick, 0) { price := div(not(0), price) }
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
// we round up in the division so getTickAtSqrtPrice of the output price is always consistent
// `sub(shl(32, 1), 1)` is `type(uint32).max`
// `price + type(uint32).max` will not overflow because `price` fits in 192 bits
sqrtPriceX96 := shr(32, add(price, sub(shl(32, 1), 1)))
}
}
}
/// @notice Calculates the greatest tick value such that getSqrtPriceAtTick(tick) <= sqrtPriceX96
/// @dev Throws in case sqrtPriceX96 < MIN_SQRT_PRICE, as MIN_SQRT_PRICE is the lowest value getSqrtPriceAtTick may
/// ever return.
/// @param sqrtPriceX96 The sqrt price for which to compute the tick as a Q64.96
/// @return tick The greatest tick for which the getSqrtPriceAtTick(tick) is less than or equal to the input sqrtPriceX96
function getTickAtSqrtPrice(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
unchecked {
// Equivalent: if (sqrtPriceX96 < MIN_SQRT_PRICE || sqrtPriceX96 >= MAX_SQRT_PRICE) revert InvalidSqrtPrice();
// second inequality must be >= because the price can never reach the price at the max tick
// if sqrtPriceX96 < MIN_SQRT_PRICE, the `sub` underflows and `gt` is true
// if sqrtPriceX96 >= MAX_SQRT_PRICE, sqrtPriceX96 - MIN_SQRT_PRICE > MAX_SQRT_PRICE - MIN_SQRT_PRICE - 1
if ((sqrtPriceX96 - MIN_SQRT_PRICE) > MAX_SQRT_PRICE_MINUS_MIN_SQRT_PRICE_MINUS_ONE) {
InvalidSqrtPrice.selector.revertWith(sqrtPriceX96);
}
uint256 price = uint256(sqrtPriceX96) << 32;
uint256 r = price;
uint256 msb = BitMath.mostSignificantBit(r);
if (msb >= 128) r = price >> (msb - 127);
else r = price << (127 - msb);
int256 log_2 = (int256(msb) - 128) << 64;
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(63, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(62, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(61, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(60, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(59, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(58, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(57, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(56, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(55, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(54, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(53, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(52, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(51, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(50, f))
}
int256 log_sqrt10001 = log_2 * 255738958999603826347141; // Q22.128 number
// Magic number represents the ceiling of the maximum value of the error when approximating log_sqrt10001(x)
int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
// Magic number represents the minimum value of the error when approximating log_sqrt10001(x), when
// sqrtPrice is from the range (2^-64, 2^64). This is safe as MIN_SQRT_PRICE is more than 2^-64. If MIN_SQRT_PRICE
// is changed, this may need to be changed too
int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);
tick = tickLow == tickHi ? tickLow : getSqrtPriceAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
}
}
}
"
},
"lib/v4-periphery/lib/v4-core/lib/solmate/src/utils/SignedWadMath.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @notice Signed 18 decimal fixed point (wad) arithmetic library.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SignedWadMath.sol)
/// @author Modified from Remco Bloemen (https://xn--2-umb.com/22/exp-ln/index.html)
/// @dev Will not revert on overflow, only use where overflow is not possible.
function toWadUnsafe(uint256 x) pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// Multiply x by 1e18.
r := mul(x, 1000000000000000000)
}
}
/// @dev Takes an integer amount of seconds and converts it to a wad amount of days.
/// @dev Will not revert on overflow, only use where overflow is not possible.
/// @dev Not meant for negative second amounts, it assumes x is positive.
function toDaysWadUnsafe(uint256 x) pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// Multiply x by 1e18 and then divide it by 86400.
r := div(mul(x, 1000000000000000000), 86400)
}
}
/// @dev Takes a wad amount of days and converts it to an integer amount of seconds.
/// @dev Will not revert on overflow, only use where overflow is not possible.
/// @dev Not meant for negative day amounts, it assumes x is positive.
function fromDaysWadUnsafe(int256 x) pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Multiply x by 86400 and then divide it by 1e18.
r := div(mul(x, 86400), 1000000000000000000)
}
}
/// @dev Will not revert on overflow, only use where overflow is not possible.
function unsafeWadMul(int256 x, int256 y) pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// Multiply x by y and divide by 1e18.
r := sdiv(mul(x, y), 1000000000000000000)
}
}
/// @dev Will return 0 instead of reverting if y is zero and will
/// not revert on overflow, only use where overflow is not possible.
function unsafeWadDiv(int256 x, int256 y) pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// Multiply x by 1e18 and divide it by y.
r := sdiv(mul(x, 1000000000000000000), y)
}
}
function wadMul(int256 x, int256 y) pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// Store x * y in r for now.
r := mul(x, y)
// Combined overflow check (`x == 0 || (x * y) / x == y`) and edge case check
// where x == -1 and y == type(int256).min, for y == -1 and x == min int256,
// the second overflow check will catch this.
// See: https://secure-contracts.com/learn_evm/arithmetic-checks.html#arithmetic-checks-for-int256-multiplication
// Combining into 1 expression saves gas as resulting bytecode will only have 1 `JUMPI`
// rather than 2.
if iszero(
and(
or(iszero(x), eq(sdiv(r, x), y)),
or(lt(x, not(0)), sgt(y, 0x8000000000000000000000000000000000000000000000000000000000000000))
)
) {
revert(0, 0)
}
// Scale the result down by 1e18.
r := sdiv(r, 1000000000000000000)
}
}
function wadDiv(int256 x, int256 y) pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// Store x * 1e18 in r for now.
r := mul(x, 1000000000000000000)
// Equivalent to require(y != 0 && ((x * 1e18) / 1e18 == x))
if iszero(and(iszero(iszero(y)), eq(sdiv(r, 1000000000000000000), x))) {
revert(0, 0)
}
// Divide r by y.
r := sdiv(r, y)
}
}
/// @dev Will not work with negative bases, only use when x is positive.
function wadPow(int256 x, int256 y) pure returns (int256) {
// Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)
return wadExp((wadLn(x) * y) / 1e18); // Using ln(x) means x must be greater than 0.
}
function wadExp(int256 x) pure returns (int256 r) {
unchecked {
// When the result is < 0.5 we return zero. This happens when
// x <= floor(log(0.5e18) * 1e18) ~ -42e18
if (x <= -42139678854452767551) return 0;
// When the result is > (2**255 - 1) / 1e18 we can not represent it as an
// int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
if (x >= 135305999368893231589) revert("EXP_OVERFLOW");
// x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
// for more intermediate precision and a binary basis. This base conversion
// is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
x = (x << 78) / 5**18;
// Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
// of two such that exp(x) = exp(x') * 2**k, where k is an integer.
// Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
x = x - k * 54916777467707473351141471128;
// k is in the range [-61, 195].
// Evaluate using a (6, 7)-term rational approximation.
// p is made monic, we'll multiply by a scale factor later.
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
// We leave p in 2**192 basis so we don't need to scale it back up for the division.
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
/// @solidity memory-safe-assembly
assembly {
// Div in assembly because solidity adds a zero check despite the unchecked.
// The q polynomial won't have zeros in the domain as all its roots are complex.
// No scaling is necessary because p is already 2**96 too large.
r := sdiv(p, q)
}
// r should be in the range (0.09, 0.25) * 2**96.
// We now need to multiply r by:
// * the scale factor s = ~6.031367120.
// * the 2**k factor from the range reduction.
// * the 1e18 / 2**96 factor for base conversion.
// We do this all at once, with an intermediate result in 2**213
// basis, so the final right shift is always by a positive amount.
r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
}
}
function wadLn(int256 x) pure returns (int256 r) {
unchecked {
require(x > 0, "UNDEFINED");
// We want to convert x from 10**18 fixed point to 2**96 fixed point.
// We do this by multiplying by 2**96 / 10**18. But since
// ln(x * C) = ln(x) + ln(C), we can simply do nothing here
// and add ln(2**96 / 10**18) at the end.
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
r := or(r, shl(2, lt(0xf, shr(r, x))))
r := or(r, shl(1, lt(0x3, shr(r, x))))
r := or(r, lt(0x1, shr(r, x)))
}
// Reduce range of x to (1, 2) * 2**96
// ln(2^k * x) = k * ln(2) + ln(x)
int256 k = r - 96;
x <<= uint256(159 - k);
x = int256(uint256(x) >> 159);
// Evaluate using a (8, 8)-term rational approximation.
// p is made monic, we will multiply by a scale factor later.
int256 p = x + 3273285459638523848632254066296;
p = ((p * x) >> 96) + 24828157081833163892658089445524;
p = ((p * x) >> 96) + 43456485725739037958740375743393;
p = ((p * x) >> 96) - 11111509109440967052023855526967;
p = ((p * x) >> 96) - 45023709667254063763336534515857;
p = ((p * x) >> 96) - 14706773417378608786704636184526;
p = p * x - (795164235651350426258249787498 << 96);
// We leave p in 2**192 basis so we don't need to scale it back up for the division.
// q is monic by convention.
int256 q = x + 5573035233440673466300451813936;
q = ((q * x) >> 96) + 71694874799317883764090561454958;
q = ((q * x) >> 96) + 283447036172924575727196451306956;
q = ((q * x) >> 96) + 401686690394027663651624208769553;
q = ((q * x) >> 96) + 204048457590392012362485061816622;
q = ((q * x) >> 96) + 31853899698501571402653359427138;
q = ((q * x) >> 96) + 909429971244387300277376558375;
/// @solidity memory-safe-assembly
assembly {
// Div in assembly because solidity adds a zero check despite the unchecked.
// The q polynomial is known not to have zeros in the domain.
// No scaling required because p is already 2**96 too large.
r := sdiv(p, q)
}
// r is in the range (0, 0.125) * 2**96
// Finalization, we need to:
// * multiply by the scale factor s = 5.549…
// * add ln(2**96 / 10**18)
// * add k * ln(2)
// * multiply by 10**18 / 2**96 = 5**18 >> 78
// mul s * 5e18 * 2**96, base is now 5**18 * 2**192
r *= 1677202110996718588342820967067443963516166;
// add ln(2) * k * 5e18 * 2**192
r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
// add ln(2**96 / 10**18) * 5e18 * 2**192
r += 600920179829731861736702779321621459595472258049074101567377883020018308;
// base conversion: mul 2**18 / 2**192
r >>= 174;
}
}
/// @dev Will return 0 instead of reverting if y is zero.
function unsafeDiv(int256 x, int256 y) pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// Divide x by y.
r := sdiv(x, y)
}
}
"
},
"lib/v4-periphery/lib/v4-core/src/libraries/FullMath.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = a * b
// Compute the product mod 2**256 and mod 2**256 - 1
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2**256 + prod0
uint256 prod0 = a * b; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
assembly ("memory-safe") {
result := div(prod0, denominator)
}
return result;
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
uint256 remainder;
assembly ("memory-safe") {
remainder := mulmod(a, b, denominator)
}
// Subtract 256 bit number from 512 bit number
assembly ("memory-safe") {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator
// Compute largest power of two divisor of denominator.
// Always >= 1.
uint256 twos = (0 - denominator) & denominator;
// Divide denominator by power of two
assembly ("memory-safe") {
denominator := div(denominator, twos)
}
// Divide [prod1 prod0] by the factors of two
assembly ("memory-safe") {
prod0 := div(prod0, twos)
}
// Shift in bits from prod1 into prod0. For this we need
// to flip `twos` such that it is 2**256 / twos.
// If twos is zero, then it becomes one
assembly ("memory-safe") {
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
// Invert denominator mod 2**256
// Now that denominator is an odd number, it has an inverse
// modulo 2**256 such that denominator * inv = 1 mod 2**256.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, denominator * inv = 1 mod 2**4
uint256 inv = (3 * denominator) ^ 2;
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv *= 2 - denominator * inv; // inverse mod 2**8
inv *= 2 - denominator * inv; // inverse mod 2**16
inv *= 2 - denominator * inv; // inverse mod 2**32
inv *= 2 - denominator * inv; // inverse mod 2**64
inv *= 2 - denominator * inv; // inverse mod 2**128
inv *= 2 - denominator * inv; // inverse mod 2**256
// Because the division is now exact we can divide by multiplying
// with the modular inverse of denominator. This will give us the
// correct result modulo 2**256. Since the preconditions guarantee
// that the outcome is less than 2**256, this is the final result.
// We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inv;
return result;
}
}
/// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
function mulDivRoundingUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
result = mulDiv(a, b, denominator);
if (mulmod(a, b, denominator) != 0) {
require(++result > 0);
}
}
}
}
"
},
"lib/v4-periphery/lib/v4-core/src/libraries/BitMath.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title BitMath
/// @dev This library provides functionality for computing bit properties of an unsigned integer
/// @author Solady (https://github.com/Vectorized/solady/blob/8200a70e8dc2a77ecb074fc2e99a2a0d36547522/src/utils/LibBit.sol)
library BitMath {
/// @notice Returns the index of the most significant bit of the number,
/// where the least significant bit is at index 0 and the most significant bit is at index 255
/// @param x the value for which to compute the most significant bit, must be greater than 0
/// @return r the index of the most significant bit
function mostSignificantBit(uint256 x) internal pure returns (uint8 r) {
require(x > 0);
assembly ("memory-safe") {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020500060203020504000106050205030304010505030400000000))
}
}
/// @notice Returns the index of the least significant bit of the number,
/// where the least significant bit is at index 0 and the most significant bit is at index 255
/// @param x the value for which to compute the least significant bit, must be greater than 0
/// @return r the index of the least significant bit
function leastSignificantBit(uint256 x) internal pure returns (uint8 r) {
require(x > 0);
assembly ("memory-safe") {
// Isolate the least significant bit.
x := and(x, sub(0, x))
// For the upper 3 bits of the result, use a De Bruijn-like lookup.
// Credit to adhusson: https://blog.adhusson.com/cheap-find-first-set-evm/
// forgefmt: disable-next-item
r := shl(5, shr(252, shl(shl(2, shr(250, mul(x,
0xb6db6db6ddddddddd34d34d349249249210842108c6318c639ce739cffffffff))),
0x8040405543005266443200005020610674053026020000107506200176117077)))
// For the lower 5 bits of the result, use a De Bruijn lookup.
// forgefmt: disable-next-item
r := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f),
0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
}
}
}
"
},
"lib/v4-periphery/lib/v4-core/src/libraries/CustomRevert.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Library for reverting with custom errors efficiently
/// @notice Contains functions for reverting with custom errors with different argument types efficiently
/// @dev To use this library, declare `using CustomRevert for bytes4;` and replace `revert CustomError()` with
/// `CustomError.selector.revertWith()`
/// @dev The functions may tamper with the free memory pointer but it is fine since the call context is exited immediately
library CustomRevert {
/// @dev ERC-7751 error for wrapping bubbled up reverts
error WrappedError(address target, bytes4 selector, bytes reason, bytes details);
/// @dev Reverts with the selector of a custom error in the scratch space
function revertWith(bytes4 selector) internal pure {
assembly ("memory-safe") {
mstore(0, selector)
revert(0, 0x04)
}
}
/// @dev Reverts with a custom error with an address argument in the scratch space
function revertWith(bytes4 selector, address addr) internal pure {
assembly ("memory-safe") {
mstore(0, selector)
mstore(0x04, and(addr, 0xffffffffffffffffffffffffffffffffffffffff))
revert(0, 0x24)
}
}
/// @dev Reverts with a custom error with an int24 argument in the scratch space
function revertWith(bytes4 selector, int24 value) internal pure {
assembly ("memory-safe") {
mstore(0, selector)
mstore(0x04, signextend(2, value))
revert(0,
Submitted on: 2025-10-29 09:18:31
Comments
Log in to comment.
No comments yet.