false
false

Contract Address Details

0xd8676fbdfa5b56bb2298d452c9768f51e80e34ae

Contract Name
AlgebraFactory
Creator
0x6c0db7–65bc41 at 0x7382a7–2969af
Balance
0 Xai ( )
Tokens
Fetching tokens...
Transactions
2 Transactions
Transfers
0 Transfers
Gas Used
6,961,016
Last Balance Update
14565819
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
AlgebraFactory




Optimization enabled
true
Compiler version
v0.7.6+commit.7338295f




Optimization runs
0
EVM Version
default




Verified at
2024-03-11T10:35:57.799286Z

Constructor Arguments

0x0000000000000000000000005822a45b05d08028baa3d19626870076d26bc460000000000000000000000000be56e9aa7792b2f1f4132631b7a0e1927090d78a

Arg [0] (address) : 0x5822a45b05d08028baa3d19626870076d26bc460
Arg [1] (address) : 0xbe56e9aa7792b2f1f4132631b7a0e1927090d78a

              

contracts/AlgebraFactory.sol

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.7.6;
pragma abicoder v2;

import './interfaces/IAlgebraFactory.sol';
import './interfaces/IAlgebraPoolDeployer.sol';
import './interfaces/IDataStorageOperator.sol';
import './libraries/AdaptiveFee.sol';
import './DataStorageOperator.sol';

/// @title Algebra factory
/// @notice Is used to deploy pools and its dataStorages
/// @dev Version: Algebra V1.9-directional-fee
contract AlgebraFactory is IAlgebraFactory {
  /// @inheritdoc IAlgebraFactory
  address public override owner;

  /// @inheritdoc IAlgebraFactory
  address public immutable override poolDeployer;

  /// @inheritdoc IAlgebraFactory
  uint8 public override defaultCommunityFee;

  /// @inheritdoc IAlgebraFactory
  address public override farmingAddress;

  /// @inheritdoc IAlgebraFactory
  address public override vaultAddress;

  // values of constants for sigmoids in fee calculation formula
  AdaptiveFee.Configuration public baseFeeConfiguration =
    AdaptiveFee.Configuration(
      3000 - Constants.BASE_FEE, // alpha1
      15000 - 3000, // alpha2
      360, // beta1
      60000, // beta2
      59, // gamma1
      8500, // gamma2
      0, // volumeBeta
      10, // volumeGamma
      Constants.BASE_FEE // baseFee
    );

  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

  /// @inheritdoc IAlgebraFactory
  mapping(address => mapping(address => address)) public override poolByPair;

  constructor(address _poolDeployer, address _vaultAddress) {
    owner = msg.sender;
    emit Owner(msg.sender);

    poolDeployer = _poolDeployer;
    vaultAddress = _vaultAddress;
  }

  /// @inheritdoc IAlgebraFactory
  function createPool(address tokenA, address tokenB) external override returns (address pool) {
    require(tokenA != tokenB);
    (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
    require(token0 != address(0));
    require(poolByPair[token0][token1] == address(0));

    IDataStorageOperator dataStorage = new DataStorageOperator(computeAddress(token0, token1));

    dataStorage.changeFeeConfiguration(true, baseFeeConfiguration);
    dataStorage.changeFeeConfiguration(false, baseFeeConfiguration);

    pool = IAlgebraPoolDeployer(poolDeployer).deploy(address(dataStorage), address(this), token0, token1);

    poolByPair[token0][token1] = pool; // to avoid future addresses comparing we are populating the mapping twice
    poolByPair[token1][token0] = pool;
    emit Pool(token0, token1, pool);
  }

  /// @inheritdoc IAlgebraFactory
  function setOwner(address _owner) external override onlyOwner {
    require(owner != _owner);
    emit Owner(_owner);
    owner = _owner;
  }

  /// @inheritdoc IAlgebraFactory
  function setFarmingAddress(address _farmingAddress) external override onlyOwner {
    require(farmingAddress != _farmingAddress);
    emit FarmingAddress(_farmingAddress);
    farmingAddress = _farmingAddress;
  }

  /// @inheritdoc IAlgebraFactory
  function setDefaultCommunityFee(uint8 newDefaultCommunityFee) external override onlyOwner {
    require(newDefaultCommunityFee <= Constants.MAX_COMMUNITY_FEE);
    require(defaultCommunityFee != newDefaultCommunityFee);
    defaultCommunityFee = newDefaultCommunityFee;
    emit DefaultCommunityFee(newDefaultCommunityFee);
  }

  /// @inheritdoc IAlgebraFactory
  function setVaultAddress(address _vaultAddress) external override onlyOwner {
    require(vaultAddress != _vaultAddress);
    emit VaultAddress(_vaultAddress);
    vaultAddress = _vaultAddress;
  }

  /// @inheritdoc IAlgebraFactory
  function setBaseFeeConfiguration(
    uint16 alpha1,
    uint16 alpha2,
    uint32 beta1,
    uint32 beta2,
    uint16 gamma1,
    uint16 gamma2,
    uint32 volumeBeta,
    uint16 volumeGamma,
    uint16 baseFee
  ) external override onlyOwner {
    require(uint256(alpha1) + uint256(alpha2) + uint256(baseFee) <= type(uint16).max, 'Max fee exceeded');
    require(gamma1 != 0 && gamma2 != 0 && volumeGamma != 0, 'Gammas must be > 0');

    baseFeeConfiguration = AdaptiveFee.Configuration(alpha1, alpha2, beta1, beta2, gamma1, gamma2, volumeBeta, volumeGamma, baseFee);
    emit FeeConfiguration(alpha1, alpha2, beta1, beta2, gamma1, gamma2, volumeBeta, volumeGamma, baseFee);
  }

  bytes32 internal constant POOL_INIT_CODE_HASH = 0x6c1bebd370ba84753516bc1393c0d0a6c645856da55f5393ac8ab3d6dbc861d3;

  /// @notice Deterministically computes the pool address given the factory and PoolKey
  /// @param token0 first token
  /// @param token1 second token
  /// @return pool The contract address of the Algebra pool
  function computeAddress(address token0, address token1) internal view returns (address pool) {
    pool = address(uint256(keccak256(abi.encodePacked(hex'ff', poolDeployer, keccak256(abi.encode(token0, token1)), POOL_INIT_CODE_HASH))));
  }
}
        

contracts/libraries/Constants.sol

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.7.6;

library Constants {
  uint8 internal constant RESOLUTION = 96;
  uint256 internal constant Q96 = 0x1000000000000000000000000;
  uint256 internal constant Q128 = 0x100000000000000000000000000000000;
  // fee value in hundredths of a bip, i.e. 1e-6
  uint16 internal constant BASE_FEE = 100;
  int24 internal constant MAX_TICK_SPACING = 500;

  // max(uint128) / (MAX_TICK - MIN_TICK)
  uint128 internal constant MAX_LIQUIDITY_PER_TICK = 191757638537527648490752896198553;

  uint32 internal constant MAX_LIQUIDITY_COOLDOWN = 1 days;
  uint8 internal constant MAX_COMMUNITY_FEE = 250;
  uint256 internal constant COMMUNITY_FEE_DENOMINATOR = 1000;
}
          

contracts/libraries/DataStorage.sol

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.7.6;

import './FullMath.sol';

/// @title DataStorage
/// @notice Provides price, liquidity, volatility data useful for a wide variety of system designs
/// @dev Instances of stored dataStorage data, "timepoints", are collected in the dataStorage array
/// Timepoints are overwritten when the full length of the dataStorage array is populated.
/// The most recent timepoint is available by passing 0 to getSingleTimepoint()
library DataStorage {
  uint32 public constant WINDOW = 1 days;
  uint256 private constant UINT16_MODULO = 65536;
  struct Timepoint {
    bool initialized; // whether or not the timepoint is initialized
    uint32 blockTimestamp; // the block timestamp of the timepoint
    int56 tickCumulative; // the tick accumulator, i.e. tick * time elapsed since the pool was first initialized
    uint160 secondsPerLiquidityCumulative; // the seconds per liquidity since the pool was first initialized
    uint88 volatilityCumulative; // the volatility accumulator; overflow after ~34800 years is desired :)
    int24 averageTick; // average tick at this blockTimestamp
    uint144 volumePerLiquidityCumulative; // the gmean(volumes)/liquidity accumulator
  }

  /// @notice Calculates volatility between two sequential timepoints with resampling to 1 sec frequency
  /// @param dt Timedelta between timepoints, must be within uint32 range
  /// @param tick0 The tick at the left timepoint, must be within int24 range
  /// @param tick1 The tick at the right timepoint, must be within int24 range
  /// @param avgTick0 The average tick at the left timepoint, must be within int24 range
  /// @param avgTick1 The average tick at the right timepoint, must be within int24 range
  /// @return volatility The volatility between two sequential timepoints
  /// If the requirements for the parameters are met, it always fits 88 bits
  function _volatilityOnRange(
    int256 dt,
    int256 tick0,
    int256 tick1,
    int256 avgTick0,
    int256 avgTick1
  ) internal pure returns (uint256 volatility) {
    // On the time interval from the previous timepoint to the current
    // we can represent tick and average tick change as two straight lines:
    // tick = k*t + b, where k and b are some constants
    // avgTick = p*t + q, where p and q are some constants
    // we want to get sum of (tick(t) - avgTick(t))^2 for every t in the interval (0; dt]
    // so: (tick(t) - avgTick(t))^2 = ((k*t + b) - (p*t + q))^2 = (k-p)^2 * t^2 + 2(k-p)(b-q)t + (b-q)^2
    // since everything except t is a constant, we need to use progressions for t and t^2:
    // sum(t) for t from 1 to dt = dt*(dt + 1)/2 = sumOfSequence
    // sum(t^2) for t from 1 to dt = dt*(dt+1)*(2dt + 1)/6 = sumOfSquares
    // so result will be: (k-p)^2 * sumOfSquares + 2(k-p)(b-q)*sumOfSequence + dt*(b-q)^2
    int256 K = (tick1 - tick0) - (avgTick1 - avgTick0); // (k - p)*dt
    int256 B = (tick0 - avgTick0) * dt; // (b - q)*dt
    int256 sumOfSquares = (dt * (dt + 1) * (2 * dt + 1)); // sumOfSquares * 6
    int256 sumOfSequence = (dt * (dt + 1)); // sumOfSequence * 2
    volatility = uint256((K**2 * sumOfSquares + 6 * B * K * sumOfSequence + 6 * dt * B**2) / (6 * dt**2));
  }

  /// @notice Transforms a previous timepoint into a new timepoint, given the passage of time and the current tick and liquidity values
  /// @dev blockTimestamp _must_ be chronologically equal to or greater than last.blockTimestamp, safe for 0 or 1 overflows
  /// @param last The specified timepoint to be used in creation of new timepoint
  /// @param blockTimestamp The timestamp of the new timepoint
  /// @param tick The active tick at the time of the new timepoint
  /// @param prevTick The active tick at the time of the last timepoint
  /// @param liquidity The total in-range liquidity at the time of the new timepoint
  /// @param averageTick The average tick at the time of the new timepoint
  /// @param volumePerLiquidity The gmean(volumes)/liquidity at the time of the new timepoint
  /// @return Timepoint The newly populated timepoint
  function createNewTimepoint(
    Timepoint memory last,
    uint32 blockTimestamp,
    int24 tick,
    int24 prevTick,
    uint128 liquidity,
    int24 averageTick,
    uint128 volumePerLiquidity
  ) private pure returns (Timepoint memory) {
    uint32 delta = blockTimestamp - last.blockTimestamp;

    last.initialized = true;
    last.blockTimestamp = blockTimestamp;
    last.tickCumulative += int56(tick) * delta;
    last.secondsPerLiquidityCumulative += ((uint160(delta) << 128) / (liquidity > 0 ? liquidity : 1)); // just timedelta if liquidity == 0
    last.volatilityCumulative += uint88(_volatilityOnRange(delta, prevTick, tick, last.averageTick, averageTick)); // always fits 88 bits
    last.averageTick = averageTick;
    last.volumePerLiquidityCumulative += volumePerLiquidity;

    return last;
  }

  /// @notice comparator for 32-bit timestamps
  /// @dev safe for 0 or 1 overflows, a and b _must_ be chronologically before or equal to currentTime
  /// @param a A comparison timestamp from which to determine the relative position of `currentTime`
  /// @param b From which to determine the relative position of `currentTime`
  /// @param currentTime A timestamp truncated to 32 bits
  /// @return res Whether `a` is chronologically <= `b`
  function lteConsideringOverflow(
    uint32 a,
    uint32 b,
    uint32 currentTime
  ) private pure returns (bool res) {
    res = a > currentTime;
    if (res == b > currentTime) res = a <= b; // if both are on the same side
  }

  /// @dev guaranteed that the result is within the bounds of int24
  /// returns int256 for fuzzy tests
  function _getAverageTick(
    Timepoint[UINT16_MODULO] storage self,
    uint32 time,
    int24 tick,
    uint16 index,
    uint16 oldestIndex,
    uint32 lastTimestamp,
    int56 lastTickCumulative
  ) internal view returns (int256 avgTick) {
    uint32 oldestTimestamp = self[oldestIndex].blockTimestamp;
    int56 oldestTickCumulative = self[oldestIndex].tickCumulative;

    if (lteConsideringOverflow(oldestTimestamp, time - WINDOW, time)) {
      if (lteConsideringOverflow(lastTimestamp, time - WINDOW, time)) {
        index -= 1; // considering underflow
        Timepoint storage startTimepoint = self[index];
        avgTick = startTimepoint.initialized
          ? (lastTickCumulative - startTimepoint.tickCumulative) / (lastTimestamp - startTimepoint.blockTimestamp)
          : tick;
      } else {
        Timepoint memory startOfWindow = getSingleTimepoint(self, time, WINDOW, tick, index, oldestIndex, 0);

        //    current-WINDOW  last   current
        // _________*____________*_______*_
        //           ||||||||||||
        avgTick = (lastTickCumulative - startOfWindow.tickCumulative) / (lastTimestamp - time + WINDOW);
      }
    } else {
      avgTick = (lastTimestamp == oldestTimestamp) ? tick : (lastTickCumulative - oldestTickCumulative) / (lastTimestamp - oldestTimestamp);
    }
  }

  /// @notice Fetches the timepoints beforeOrAt and atOrAfter a target, i.e. where [beforeOrAt, atOrAfter] is satisfied.
  /// The result may be the same timepoint, or adjacent timepoints.
  /// @dev The answer must be contained in the array, used when the target is located within the stored timepoint
  /// boundaries: older than the most recent timepoint and younger, or the same age as, the oldest timepoint
  /// @param self The stored dataStorage array
  /// @param time The current block.timestamp
  /// @param target The timestamp at which the reserved timepoint should be for
  /// @param lastIndex The index of the timepoint that was most recently written to the timepoints array
  /// @param oldestIndex The index of the oldest timepoint in the timepoints array
  /// @return beforeOrAt The timepoint recorded before, or at, the target
  /// @return atOrAfter The timepoint recorded at, or after, the target
  function binarySearch(
    Timepoint[UINT16_MODULO] storage self,
    uint32 time,
    uint32 target,
    uint16 lastIndex,
    uint16 oldestIndex
  ) private view returns (Timepoint storage beforeOrAt, Timepoint storage atOrAfter) {
    uint256 left = oldestIndex; // oldest timepoint
    uint256 right = lastIndex >= oldestIndex ? lastIndex : lastIndex + UINT16_MODULO; // newest timepoint considering one index overflow
    uint256 current = (left + right) >> 1; // "middle" point between the boundaries

    do {
      beforeOrAt = self[uint16(current)]; // checking the "middle" point between the boundaries
      (bool initializedBefore, uint32 timestampBefore) = (beforeOrAt.initialized, beforeOrAt.blockTimestamp);
      if (initializedBefore) {
        if (lteConsideringOverflow(timestampBefore, target, time)) {
          // is current point before or at `target`?
          atOrAfter = self[uint16(current + 1)]; // checking the next point after "middle"
          (bool initializedAfter, uint32 timestampAfter) = (atOrAfter.initialized, atOrAfter.blockTimestamp);
          if (initializedAfter) {
            if (lteConsideringOverflow(target, timestampAfter, time)) {
              // is the "next" point after or at `target`?
              return (beforeOrAt, atOrAfter); // the only fully correct way to finish
            }
            left = current + 1; // "next" point is before the `target`, so looking in the right half
          } else {
            // beforeOrAt is initialized and <= target, and next timepoint is uninitialized
            // should be impossible if initial boundaries and `target` are correct
            return (beforeOrAt, beforeOrAt);
          }
        } else {
          right = current - 1; // current point is after the `target`, so looking in the left half
        }
      } else {
        // we've landed on an uninitialized timepoint, keep searching higher
        // should be impossible if initial boundaries and `target` are correct
        left = current + 1;
      }
      current = (left + right) >> 1; // calculating the new "middle" point index after updating the bounds
    } while (true);

    atOrAfter = beforeOrAt; // code is unreachable, to suppress compiler warning
    assert(false);
  }

  /// @dev Reverts if an timepoint at or before the desired timepoint timestamp does not exist.
  /// 0 may be passed as `secondsAgo' to return the current cumulative values.
  /// If called with a timestamp falling between two timepoints, returns the counterfactual accumulator values
  /// at exactly the timestamp between the two timepoints.
  /// @param self The stored dataStorage array
  /// @param time The current block timestamp
  /// @param secondsAgo The amount of time to look back, in seconds, at which point to return an timepoint
  /// @param tick The current tick
  /// @param index The index of the timepoint that was most recently written to the timepoints array
  /// @param oldestIndex The index of the oldest timepoint
  /// @param liquidity The current in-range pool liquidity
  /// @return targetTimepoint desired timepoint or it's approximation
  function getSingleTimepoint(
    Timepoint[UINT16_MODULO] storage self,
    uint32 time,
    uint32 secondsAgo,
    int24 tick,
    uint16 index,
    uint16 oldestIndex,
    uint128 liquidity
  ) internal view returns (Timepoint memory targetTimepoint) {
    uint32 target = time - secondsAgo;

    // if target is newer than last timepoint
    if (secondsAgo == 0 || lteConsideringOverflow(self[index].blockTimestamp, target, time)) {
      Timepoint memory last = self[index];
      if (last.blockTimestamp == target) {
        return last;
      } else {
        // otherwise, we need to add new timepoint
        int24 avgTick = int24(_getAverageTick(self, time, tick, index, oldestIndex, last.blockTimestamp, last.tickCumulative));
        int24 prevTick = tick;
        {
          if (index != oldestIndex) {
            Timepoint memory prevLast;
            Timepoint storage _prevLast = self[index - 1]; // considering index underflow
            prevLast.blockTimestamp = _prevLast.blockTimestamp;
            prevLast.tickCumulative = _prevLast.tickCumulative;
            prevTick = int24((last.tickCumulative - prevLast.tickCumulative) / (last.blockTimestamp - prevLast.blockTimestamp));
          }
        }
        return createNewTimepoint(last, target, tick, prevTick, liquidity, avgTick, 0);
      }
    }

    require(lteConsideringOverflow(self[oldestIndex].blockTimestamp, target, time), 'OLD');
    (Timepoint memory beforeOrAt, Timepoint memory atOrAfter) = binarySearch(self, time, target, index, oldestIndex);

    if (target == atOrAfter.blockTimestamp) {
      return atOrAfter; // we're at the right boundary
    }

    if (target != beforeOrAt.blockTimestamp) {
      // we're in the middle
      uint32 timepointTimeDelta = atOrAfter.blockTimestamp - beforeOrAt.blockTimestamp;
      uint32 targetDelta = target - beforeOrAt.blockTimestamp;

      // For gas savings the resulting point is written to beforeAt
      beforeOrAt.tickCumulative += ((atOrAfter.tickCumulative - beforeOrAt.tickCumulative) / timepointTimeDelta) * targetDelta;
      beforeOrAt.secondsPerLiquidityCumulative += uint160(
        (uint256(atOrAfter.secondsPerLiquidityCumulative - beforeOrAt.secondsPerLiquidityCumulative) * targetDelta) / timepointTimeDelta
      );
      beforeOrAt.volatilityCumulative += ((atOrAfter.volatilityCumulative - beforeOrAt.volatilityCumulative) / timepointTimeDelta) * targetDelta;
      beforeOrAt.volumePerLiquidityCumulative +=
        ((atOrAfter.volumePerLiquidityCumulative - beforeOrAt.volumePerLiquidityCumulative) / timepointTimeDelta) *
        targetDelta;
    }

    // we're at the left boundary or at the middle
    return beforeOrAt;
  }

  /// @notice Returns the accumulator values as of each time seconds ago from the given time in the array of `secondsAgos`
  /// @dev Reverts if `secondsAgos` > oldest timepoint
  /// @param self The stored dataStorage array
  /// @param time The current block.timestamp
  /// @param secondsAgos Each amount of time to look back, in seconds, at which point to return an timepoint
  /// @param tick The current tick
  /// @param index The index of the timepoint that was most recently written to the timepoints array
  /// @param liquidity The current in-range pool liquidity
  /// @return tickCumulatives The tick * time elapsed since the pool was first initialized, as of each `secondsAgo`
  /// @return secondsPerLiquidityCumulatives The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of each `secondsAgo`
  /// @return volatilityCumulatives The cumulative volatility values since the pool was first initialized, as of each `secondsAgo`
  /// @return volumePerAvgLiquiditys The cumulative volume per liquidity values since the pool was first initialized, as of each `secondsAgo`
  function getTimepoints(
    Timepoint[UINT16_MODULO] storage self,
    uint32 time,
    uint32[] memory secondsAgos,
    int24 tick,
    uint16 index,
    uint128 liquidity
  )
    internal
    view
    returns (
      int56[] memory tickCumulatives,
      uint160[] memory secondsPerLiquidityCumulatives,
      uint112[] memory volatilityCumulatives,
      uint256[] memory volumePerAvgLiquiditys
    )
  {
    tickCumulatives = new int56[](secondsAgos.length);
    secondsPerLiquidityCumulatives = new uint160[](secondsAgos.length);
    volatilityCumulatives = new uint112[](secondsAgos.length);
    volumePerAvgLiquiditys = new uint256[](secondsAgos.length);

    uint16 oldestIndex;
    // check if we have overflow in the past
    uint16 nextIndex = index + 1; // considering overflow
    if (self[nextIndex].initialized) {
      oldestIndex = nextIndex;
    }

    Timepoint memory current;
    for (uint256 i = 0; i < secondsAgos.length; i++) {
      current = getSingleTimepoint(self, time, secondsAgos[i], tick, index, oldestIndex, liquidity);
      (tickCumulatives[i], secondsPerLiquidityCumulatives[i], volatilityCumulatives[i], volumePerAvgLiquiditys[i]) = (
        current.tickCumulative,
        current.secondsPerLiquidityCumulative,
        current.volatilityCumulative,
        current.volumePerLiquidityCumulative
      );
    }
  }

  /// @notice Returns average volatility in the range from time-WINDOW to time
  /// @param self The stored dataStorage array
  /// @param time The current block.timestamp
  /// @param tick The current tick
  /// @param index The index of the timepoint that was most recently written to the timepoints array
  /// @param liquidity The current in-range pool liquidity
  /// @return volatilityAverage The average volatility in the recent range
  /// @return volumePerLiqAverage The average volume per liquidity in the recent range
  function getAverages(
    Timepoint[UINT16_MODULO] storage self,
    uint32 time,
    int24 tick,
    uint16 index,
    uint128 liquidity
  ) internal view returns (uint88 volatilityAverage, uint256 volumePerLiqAverage) {
    uint16 oldestIndex;
    Timepoint storage oldest = self[0];
    uint16 nextIndex = index + 1; // considering overflow
    if (self[nextIndex].initialized) {
      oldest = self[nextIndex];
      oldestIndex = nextIndex;
    }

    Timepoint memory endOfWindow = getSingleTimepoint(self, time, 0, tick, index, oldestIndex, liquidity);

    uint32 oldestTimestamp = oldest.blockTimestamp;
    if (lteConsideringOverflow(oldestTimestamp, time - WINDOW, time)) {
      Timepoint memory startOfWindow = getSingleTimepoint(self, time, WINDOW, tick, index, oldestIndex, liquidity);
      return (
        (endOfWindow.volatilityCumulative - startOfWindow.volatilityCumulative) / WINDOW,
        uint256(endOfWindow.volumePerLiquidityCumulative - startOfWindow.volumePerLiquidityCumulative) >> 57
      );
    } else if (time != oldestTimestamp) {
      uint88 _oldestVolatilityCumulative = oldest.volatilityCumulative;
      uint144 _oldestVolumePerLiquidityCumulative = oldest.volumePerLiquidityCumulative;
      return (
        (endOfWindow.volatilityCumulative - _oldestVolatilityCumulative) / (time - oldestTimestamp),
        uint256(endOfWindow.volumePerLiquidityCumulative - _oldestVolumePerLiquidityCumulative) >> 57
      );
    }
  }

  /// @notice Initialize the dataStorage array by writing the first slot. Called once for the lifecycle of the timepoints array
  /// @param self The stored dataStorage array
  /// @param time The time of the dataStorage initialization, via block.timestamp truncated to uint32
  /// @param tick Initial tick
  function initialize(
    Timepoint[UINT16_MODULO] storage self,
    uint32 time,
    int24 tick
  ) internal {
    require(!self[0].initialized);
    self[0].initialized = true;
    self[0].blockTimestamp = time;
    self[0].averageTick = tick;
  }

  /// @notice Writes an dataStorage timepoint to the array
  /// @dev Writable at most once per block. Index represents the most recently written element. index must be tracked externally.
  /// @param self The stored dataStorage array
  /// @param index The index of the timepoint that was most recently written to the timepoints array
  /// @param blockTimestamp The timestamp of the new timepoint
  /// @param tick The active tick at the time of the new timepoint
  /// @param liquidity The total in-range liquidity at the time of the new timepoint
  /// @param volumePerLiquidity The gmean(volumes)/liquidity at the time of the new timepoint
  /// @return indexUpdated The new index of the most recently written element in the dataStorage array
  function write(
    Timepoint[UINT16_MODULO] storage self,
    uint16 index,
    uint32 blockTimestamp,
    int24 tick,
    uint128 liquidity,
    uint128 volumePerLiquidity
  ) internal returns (uint16 indexUpdated) {
    Timepoint storage _last = self[index];
    // early return if we've already written an timepoint this block
    if (_last.blockTimestamp == blockTimestamp) {
      return index;
    }
    Timepoint memory last = _last;

    // get next index considering overflow
    indexUpdated = index + 1;

    uint16 oldestIndex;
    // check if we have overflow in the past
    if (self[indexUpdated].initialized) {
      oldestIndex = indexUpdated;
    }

    int24 avgTick = int24(_getAverageTick(self, blockTimestamp, tick, index, oldestIndex, last.blockTimestamp, last.tickCumulative));
    int24 prevTick = tick;
    if (index != oldestIndex) {
      Timepoint storage _prevLast = self[index - 1]; // considering index underflow
      uint32 _prevLastBlockTimestamp = _prevLast.blockTimestamp;
      int56 _prevLastTickCumulative = _prevLast.tickCumulative;
      prevTick = int24((last.tickCumulative - _prevLastTickCumulative) / (last.blockTimestamp - _prevLastBlockTimestamp));
    }

    self[indexUpdated] = createNewTimepoint(last, blockTimestamp, tick, prevTick, liquidity, avgTick, volumePerLiquidity);
  }
}
          

contracts/libraries/FullMath.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.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) {
    // 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 {
      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 {
        result := div(prod0, denominator)
      }
      return result;
    }

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

    // Make division exact by subtracting the remainder from [prod1 prod0]
    // Compute remainder using mulmod
    // Subtract 256 bit remainder from 512 bit number
    assembly {
      let remainder := mulmod(a, b, denominator)
      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 = -denominator & denominator;
    // Divide denominator by power of two
    assembly {
      denominator := div(denominator, twos)
    }

    // Divide [prod1 prod0] by the factors of two
    assembly {
      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 {
      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) {
    if (a == 0 || ((result = a * b) / a == b)) {
      require(denominator > 0);
      assembly {
        result := add(div(result, denominator), gt(mod(result, denominator), 0))
      }
    } else {
      result = mulDiv(a, b, denominator);
      if (mulmod(a, b, denominator) > 0) {
        require(result < type(uint256).max);
        result++;
      }
    }
  }

  /// @notice Returns ceil(x / y)
  /// @dev division by 0 has unspecified behavior, and must be checked externally
  /// @param x The dividend
  /// @param y The divisor
  /// @return z The quotient, ceil(x / y)
  function divRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
    assembly {
      z := add(div(x, y), gt(mod(x, y), 0))
    }
  }
}
          

contracts/libraries/AdaptiveFee.sol

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.7.6;

import './Constants.sol';

/// @title AdaptiveFee
/// @notice Calculates fee based on combination of sigmoids
library AdaptiveFee {
  // alpha1 + alpha2 + baseFee must be <= type(uint16).max
  struct Configuration {
    uint16 alpha1; // max value of the first sigmoid
    uint16 alpha2; // max value of the second sigmoid
    uint32 beta1; // shift along the x-axis for the first sigmoid
    uint32 beta2; // shift along the x-axis for the second sigmoid
    uint16 gamma1; // horizontal stretch factor for the first sigmoid
    uint16 gamma2; // horizontal stretch factor for the second sigmoid
    uint32 volumeBeta; // shift along the x-axis for the outer volume-sigmoid
    uint16 volumeGamma; // horizontal stretch factor the outer volume-sigmoid
    uint16 baseFee; // minimum possible fee
  }

  /// @notice Calculates fee based on formula:
  /// baseFee + sigmoidVolume(sigmoid1(volatility, volumePerLiquidity) + sigmoid2(volatility, volumePerLiquidity))
  /// maximum value capped by baseFee + alpha1 + alpha2
  function getFee(
    uint88 volatility,
    uint256 volumePerLiquidity,
    Configuration memory config
  ) internal pure returns (uint16 fee) {
    uint256 sumOfSigmoids = sigmoid(volatility, config.gamma1, config.alpha1, config.beta1) +
      sigmoid(volatility, config.gamma2, config.alpha2, config.beta2);

    if (sumOfSigmoids > type(uint16).max) {
      // should be impossible, just in case
      sumOfSigmoids = type(uint16).max;
    }

    return uint16(config.baseFee + sigmoid(volumePerLiquidity, config.volumeGamma, uint16(sumOfSigmoids), config.volumeBeta)); // safe since alpha1 + alpha2 + baseFee _must_ be <= type(uint16).max
  }

  /// @notice calculates α / (1 + e^( (β-x) / γ))
  /// that is a sigmoid with a maximum value of α, x-shifted by β, and stretched by γ
  /// @dev returns uint256 for fuzzy testing. Guaranteed that the result is not greater than alpha
  function sigmoid(
    uint256 x,
    uint16 g,
    uint16 alpha,
    uint256 beta
  ) internal pure returns (uint256 res) {
    if (x > beta) {
      x = x - beta;
      if (x >= 6 * uint256(g)) return alpha; // so x < 19 bits
      uint256 g8 = uint256(g)**8; // < 128 bits (8*16)
      uint256 ex = exp(x, g, g8); // < 155 bits
      res = (alpha * ex) / (g8 + ex); // in worst case: (16 + 155 bits) / 155 bits
      // so res <= alpha
    } else {
      x = beta - x;
      if (x >= 6 * uint256(g)) return 0; // so x < 19 bits
      uint256 g8 = uint256(g)**8; // < 128 bits (8*16)
      uint256 ex = g8 + exp(x, g, g8); // < 156 bits
      res = (alpha * g8) / ex; // in worst case: (16 + 128 bits) / 156 bits
      // g8 <= ex, so res <= alpha
    }
  }

  /// @notice calculates e^(x/g) * g^8 in a series, since (around zero):
  /// e^x = 1 + x + x^2/2 + ... + x^n/n! + ...
  /// e^(x/g) = 1 + x/g + x^2/(2*g^2) + ... + x^(n)/(g^n * n!) + ...
  function exp(
    uint256 x,
    uint16 g,
    uint256 gHighestDegree
  ) internal pure returns (uint256 res) {
    // calculating:
    // g**8 + x * g**7 + (x**2 * g**6) / 2 + (x**3 * g**5) / 6 + (x**4 * g**4) / 24 + (x**5 * g**3) / 120 + (x**6 * g^2) / 720 + x**7 * g / 5040 + x**8 / 40320

    // x**8 < 152 bits (19*8) and g**8 < 128 bits (8*16)
    // so each summand < 152 bits and res < 155 bits
    uint256 xLowestDegree = x;
    res = gHighestDegree; // g**8

    gHighestDegree /= g; // g**7
    res += xLowestDegree * gHighestDegree;

    gHighestDegree /= g; // g**6
    xLowestDegree *= x; // x**2
    res += (xLowestDegree * gHighestDegree) / 2;

    gHighestDegree /= g; // g**5
    xLowestDegree *= x; // x**3
    res += (xLowestDegree * gHighestDegree) / 6;

    gHighestDegree /= g; // g**4
    xLowestDegree *= x; // x**4
    res += (xLowestDegree * gHighestDegree) / 24;

    gHighestDegree /= g; // g**3
    xLowestDegree *= x; // x**5
    res += (xLowestDegree * gHighestDegree) / 120;

    gHighestDegree /= g; // g**2
    xLowestDegree *= x; // x**6
    res += (xLowestDegree * gHighestDegree) / 720;

    xLowestDegree *= x; // x**7
    res += (xLowestDegree * g) / 5040 + (xLowestDegree * x) / (40320);
  }
}
          

contracts/DataStorageOperator.sol

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.7.6;
pragma abicoder v2;

import './interfaces/IAlgebraFactory.sol';
import './interfaces/IDataStorageOperator.sol';

import './libraries/DataStorage.sol';
import './libraries/Sqrt.sol';
import './libraries/AdaptiveFee.sol';

import './libraries/Constants.sol';

/// @title Algebra timepoints data operator
/// @notice This contract stores timepoints and calculates adaptive fee and statistical averages
contract DataStorageOperator is IDataStorageOperator {
  uint256 constant UINT16_MODULO = 65536;
  uint128 constant MAX_VOLUME_PER_LIQUIDITY = 100000 << 64; // maximum meaningful ratio of volume to liquidity

  using DataStorage for DataStorage.Timepoint[UINT16_MODULO];

  DataStorage.Timepoint[UINT16_MODULO] public override timepoints;

  AdaptiveFee.Configuration public feeConfigZto;
  AdaptiveFee.Configuration public feeConfigOtz;

  address private immutable pool;
  address private immutable factory;

  modifier onlyPool() {
    require(msg.sender == pool, 'only pool can call this');
    _;
  }

  constructor(address _pool) {
    factory = msg.sender;
    pool = _pool;
  }

  /// @inheritdoc IDataStorageOperator
  function initialize(uint32 time, int24 tick) external override onlyPool {
    return timepoints.initialize(time, tick);
  }

  /// @inheritdoc IDataStorageOperator
  function changeFeeConfiguration(bool zto, AdaptiveFee.Configuration calldata _feeConfig) external override {
    require(msg.sender == factory || msg.sender == IAlgebraFactory(factory).owner());

    require(uint256(_feeConfig.alpha1) + uint256(_feeConfig.alpha2) + uint256(_feeConfig.baseFee) <= type(uint16).max, 'Max fee exceeded');
    require(_feeConfig.gamma1 != 0 && _feeConfig.gamma2 != 0 && _feeConfig.volumeGamma != 0, 'Gammas must be > 0');

    if (zto) feeConfigZto = _feeConfig;
    else feeConfigOtz = _feeConfig;
    emit FeeConfiguration(zto, _feeConfig);
  }

  /// @inheritdoc IDataStorageOperator
  function getSingleTimepoint(
    uint32 time,
    uint32 secondsAgo,
    int24 tick,
    uint16 index,
    uint128 liquidity
  )
    external
    view
    override
    onlyPool
    returns (int56 tickCumulative, uint160 secondsPerLiquidityCumulative, uint112 volatilityCumulative, uint256 volumePerAvgLiquidity)
  {
    uint16 oldestIndex;
    // check if we have overflow in the past
    uint16 nextIndex = index + 1; // considering overflow
    if (timepoints[nextIndex].initialized) {
      oldestIndex = nextIndex;
    }

    DataStorage.Timepoint memory result = timepoints.getSingleTimepoint(time, secondsAgo, tick, index, oldestIndex, liquidity);
    (tickCumulative, secondsPerLiquidityCumulative, volatilityCumulative, volumePerAvgLiquidity) = (
      result.tickCumulative,
      result.secondsPerLiquidityCumulative,
      result.volatilityCumulative,
      result.volumePerLiquidityCumulative
    );
  }

  /// @inheritdoc IDataStorageOperator
  function getTimepoints(
    uint32 time,
    uint32[] memory secondsAgos,
    int24 tick,
    uint16 index,
    uint128 liquidity
  )
    external
    view
    override
    onlyPool
    returns (
      int56[] memory tickCumulatives,
      uint160[] memory secondsPerLiquidityCumulatives,
      uint112[] memory volatilityCumulatives,
      uint256[] memory volumePerAvgLiquiditys
    )
  {
    return timepoints.getTimepoints(time, secondsAgos, tick, index, liquidity);
  }

  /// @inheritdoc IDataStorageOperator
  function getAverages(
    uint32 time,
    int24 tick,
    uint16 index,
    uint128 liquidity
  ) external view override onlyPool returns (uint112 TWVolatilityAverage, uint256 TWVolumePerLiqAverage) {
    return timepoints.getAverages(time, tick, index, liquidity);
  }

  /// @inheritdoc IDataStorageOperator
  function write(
    uint16 index,
    uint32 blockTimestamp,
    int24 tick,
    uint128 liquidity,
    uint128 volumePerLiquidity
  ) external override onlyPool returns (uint16 indexUpdated) {
    return timepoints.write(index, blockTimestamp, tick, liquidity, volumePerLiquidity);
  }

  /// @inheritdoc IDataStorageOperator
  function calculateVolumePerLiquidity(
    uint128 liquidity,
    int256 amount0,
    int256 amount1
  ) external pure override returns (uint128 volumePerLiquidity) {
    uint256 volume = Sqrt.sqrtAbs(amount0) * Sqrt.sqrtAbs(amount1);
    uint256 volumeShifted;
    if (volume >= 2 ** 192) volumeShifted = (type(uint256).max) / (liquidity > 0 ? liquidity : 1);
    else volumeShifted = (volume << 64) / (liquidity > 0 ? liquidity : 1);
    if (volumeShifted >= MAX_VOLUME_PER_LIQUIDITY) return MAX_VOLUME_PER_LIQUIDITY;
    else return uint128(volumeShifted);
  }

  /// @inheritdoc IDataStorageOperator
  function window() external pure override returns (uint32) {
    return DataStorage.WINDOW;
  }

  /// @inheritdoc IDataStorageOperator
  function getFees(
    uint32 _time,
    int24 _tick,
    uint16 _index,
    uint128 _liquidity
  ) external view override onlyPool returns (uint16 feeZto, uint16 feeOtz) {
    (uint88 volatilityAverage, uint256 volumePerLiqAverage) = timepoints.getAverages(_time, _tick, _index, _liquidity);

    feeZto = AdaptiveFee.getFee(volatilityAverage / 15, volumePerLiqAverage, feeConfigZto);
    feeOtz = AdaptiveFee.getFee(volatilityAverage / 15, volumePerLiqAverage, feeConfigOtz);
  }
}
          

contracts/interfaces/IAlgebraFactory.sol

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/**
 * @title The interface for the Algebra Factory
 * @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
 * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
 */
interface IAlgebraFactory {
  /**
   * @notice Emitted when the owner of the factory is changed
   * @param newOwner The owner after the owner was changed
   */
  event Owner(address indexed newOwner);

  /**
   * @notice Emitted when the vault address is changed
   * @param newVaultAddress The vault address after the address was changed
   */
  event VaultAddress(address indexed newVaultAddress);

  /**
   * @notice Emitted when a pool is created
   * @param token0 The first token of the pool by address sort order
   * @param token1 The second token of the pool by address sort order
   * @param pool The address of the created pool
   */
  event Pool(address indexed token0, address indexed token1, address pool);

  /**
   * @notice Emitted when the farming address is changed
   * @param newFarmingAddress The farming address after the address was changed
   */
  event FarmingAddress(address indexed newFarmingAddress);

  /**
   * @notice Emitted when the default community fee is changed
   * @param newDefaultCommunityFee The new default community fee value
   */
  event DefaultCommunityFee(uint8 newDefaultCommunityFee);

  event FeeConfiguration(
    uint16 alpha1,
    uint16 alpha2,
    uint32 beta1,
    uint32 beta2,
    uint16 gamma1,
    uint16 gamma2,
    uint32 volumeBeta,
    uint16 volumeGamma,
    uint16 baseFee
  );

  /**
   * @notice Returns the current owner of the factory
   * @dev Can be changed by the current owner via setOwner
   * @return The address of the factory owner
   */
  function owner() external view returns (address);

  /**
   * @notice Returns the current poolDeployerAddress
   * @return The address of the poolDeployer
   */
  function poolDeployer() external view returns (address);

  /**
   * @dev Is retrieved from the pools to restrict calling
   * certain functions not by a tokenomics contract
   * @return The tokenomics contract address
   */
  function farmingAddress() external view returns (address);

  /**
   * @notice Returns the default community fee
   * @return Fee which will be set at the creation of the pool
   */
  function defaultCommunityFee() external view returns (uint8);

  function vaultAddress() external view returns (address);

  /**
   * @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist
   * @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order
   * @param tokenA The contract address of either token0 or token1
   * @param tokenB The contract address of the other token
   * @return pool The pool address
   */
  function poolByPair(address tokenA, address tokenB) external view returns (address pool);

  /**
   * @notice Creates a pool for the given two tokens and fee
   * @param tokenA One of the two tokens in the desired pool
   * @param tokenB The other of the two tokens in the desired pool
   * @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved
   * from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments
   * are invalid.
   * @return pool The address of the newly created pool
   */
  function createPool(address tokenA, address tokenB) external returns (address pool);

  /**
   * @notice Updates the owner of the factory
   * @dev Must be called by the current owner
   * @param _owner The new owner of the factory
   */
  function setOwner(address _owner) external;

  /**
   * @dev updates tokenomics address on the factory
   * @param _farmingAddress The new tokenomics contract address
   */
  function setFarmingAddress(address _farmingAddress) external;

  /**
   * @dev updates default community fee for new pools
   * @param newDefaultCommunityFee The new community fee, _must_ be <= MAX_COMMUNITY_FEE
   */
  function setDefaultCommunityFee(uint8 newDefaultCommunityFee) external;

  /**
   * @dev updates vault address on the factory
   * @param _vaultAddress The new vault contract address
   */
  function setVaultAddress(address _vaultAddress) external;

  /**
   * @notice Changes initial fee configuration for new pools
   * @dev changes coefficients for sigmoids: α / (1 + e^( (β-x) / γ))
   * alpha1 + alpha2 + baseFee (max possible fee) must be <= type(uint16).max
   * gammas must be > 0
   * @param alpha1 max value of the first sigmoid
   * @param alpha2 max value of the second sigmoid
   * @param beta1 shift along the x-axis for the first sigmoid
   * @param beta2 shift along the x-axis for the second sigmoid
   * @param gamma1 horizontal stretch factor for the first sigmoid
   * @param gamma2 horizontal stretch factor for the second sigmoid
   * @param volumeBeta shift along the x-axis for the outer volume-sigmoid
   * @param volumeGamma horizontal stretch factor the outer volume-sigmoid
   * @param baseFee minimum possible fee
   */
  function setBaseFeeConfiguration(
    uint16 alpha1,
    uint16 alpha2,
    uint32 beta1,
    uint32 beta2,
    uint16 gamma1,
    uint16 gamma2,
    uint32 volumeBeta,
    uint16 volumeGamma,
    uint16 baseFee
  ) external;
}
          

contracts/interfaces/IAlgebraPoolDeployer.sol

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/**
 * @title An interface for a contract that is capable of deploying Algebra Pools
 * @notice A contract that constructs a pool must implement this to pass arguments to the pool
 * @dev This is used to avoid having constructor arguments in the pool contract, which results in the init code hash
 * of the pool being constant allowing the CREATE2 address of the pool to be cheaply computed on-chain.
 * Credit to Uniswap Labs under GPL-2.0-or-later license:
 * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
 */
interface IAlgebraPoolDeployer {
  /**
   * @notice Emitted when the factory address is changed
   * @param factory The factory address after the address was changed
   */
  event Factory(address indexed factory);

  /**
   * @notice Get the parameters to be used in constructing the pool, set transiently during pool creation.
   * @dev Called by the pool constructor to fetch the parameters of the pool
   * Returns dataStorage The pools associated dataStorage
   * Returns factory The factory address
   * Returns token0 The first token of the pool by address sort order
   * Returns token1 The second token of the pool by address sort order
   */
  function parameters() external view returns (address dataStorage, address factory, address token0, address token1);

  /**
   * @dev Deploys a pool with the given parameters by transiently setting the parameters storage slot and then
   * clearing it after deploying the pool.
   * @param dataStorage The pools associated dataStorage
   * @param factory The contract address of the Algebra factory
   * @param token0 The first token of the pool by address sort order
   * @param token1 The second token of the pool by address sort order
   * @return pool The deployed pool's address
   */
  function deploy(address dataStorage, address factory, address token0, address token1) external returns (address pool);

  /**
   * @dev Sets the factory address to the poolDeployer for permissioned actions
   * @param factory The address of the Algebra factory
   */
  function setFactory(address factory) external;
}
          

contracts/interfaces/IDataStorageOperator.sol

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
pragma abicoder v2;

import '../libraries/AdaptiveFee.sol';

interface IDataStorageOperator {
  event FeeConfiguration(bool zto, AdaptiveFee.Configuration feeConfig);

  /**
   * @notice Returns data belonging to a certain timepoint
   * @param index The index of timepoint in the array
   * @dev There is more convenient function to fetch a timepoint: getTimepoints(). Which requires not an index but seconds
   * @return initialized Whether the timepoint has been initialized and the values are safe to use,
   * blockTimestamp The timestamp of the observation,
   * tickCumulative The tick multiplied by seconds elapsed for the life of the pool as of the timepoint timestamp,
   * secondsPerLiquidityCumulative The seconds per in range liquidity for the life of the pool as of the timepoint timestamp,
   * volatilityCumulative Cumulative standard deviation for the life of the pool as of the timepoint timestamp,
   * averageTick Time-weighted average tick,
   * volumePerLiquidityCumulative Cumulative swap volume per liquidity for the life of the pool as of the timepoint timestamp
   */
  function timepoints(uint256 index)
    external
    view
    returns (
      bool initialized,
      uint32 blockTimestamp,
      int56 tickCumulative,
      uint160 secondsPerLiquidityCumulative,
      uint88 volatilityCumulative,
      int24 averageTick,
      uint144 volumePerLiquidityCumulative
    );

  /// @notice Initialize the dataStorage array by writing the first slot. Called once for the lifecycle of the timepoints array
  /// @param time The time of the dataStorage initialization, via block.timestamp truncated to uint32
  /// @param tick Initial tick
  function initialize(uint32 time, int24 tick) external;

  /// @dev Reverts if an timepoint at or before the desired timepoint timestamp does not exist.
  /// 0 may be passed as `secondsAgo' to return the current cumulative values.
  /// If called with a timestamp falling between two timepoints, returns the counterfactual accumulator values
  /// at exactly the timestamp between the two timepoints.
  /// @param time The current block timestamp
  /// @param secondsAgo The amount of time to look back, in seconds, at which point to return an timepoint
  /// @param tick The current tick
  /// @param index The index of the timepoint that was most recently written to the timepoints array
  /// @param liquidity The current in-range pool liquidity
  /// @return tickCumulative The cumulative tick since the pool was first initialized, as of `secondsAgo`
  /// @return secondsPerLiquidityCumulative The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of `secondsAgo`
  /// @return volatilityCumulative The cumulative volatility value since the pool was first initialized, as of `secondsAgo`
  /// @return volumePerAvgLiquidity The cumulative volume per liquidity value since the pool was first initialized, as of `secondsAgo`
  function getSingleTimepoint(
    uint32 time,
    uint32 secondsAgo,
    int24 tick,
    uint16 index,
    uint128 liquidity
  )
    external
    view
    returns (
      int56 tickCumulative,
      uint160 secondsPerLiquidityCumulative,
      uint112 volatilityCumulative,
      uint256 volumePerAvgLiquidity
    );

  /// @notice Returns the accumulator values as of each time seconds ago from the given time in the array of `secondsAgos`
  /// @dev Reverts if `secondsAgos` > oldest timepoint
  /// @param time The current block.timestamp
  /// @param secondsAgos Each amount of time to look back, in seconds, at which point to return an timepoint
  /// @param tick The current tick
  /// @param index The index of the timepoint that was most recently written to the timepoints array
  /// @param liquidity The current in-range pool liquidity
  /// @return tickCumulatives The cumulative tick since the pool was first initialized, as of each `secondsAgo`
  /// @return secondsPerLiquidityCumulatives The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of each `secondsAgo`
  /// @return volatilityCumulatives The cumulative volatility values since the pool was first initialized, as of each `secondsAgo`
  /// @return volumePerAvgLiquiditys The cumulative volume per liquidity values since the pool was first initialized, as of each `secondsAgo`
  function getTimepoints(
    uint32 time,
    uint32[] memory secondsAgos,
    int24 tick,
    uint16 index,
    uint128 liquidity
  )
    external
    view
    returns (
      int56[] memory tickCumulatives,
      uint160[] memory secondsPerLiquidityCumulatives,
      uint112[] memory volatilityCumulatives,
      uint256[] memory volumePerAvgLiquiditys
    );

  /// @notice Returns average volatility in the range from time-WINDOW to time
  /// @param time The current block.timestamp
  /// @param tick The current tick
  /// @param index The index of the timepoint that was most recently written to the timepoints array
  /// @param liquidity The current in-range pool liquidity
  /// @return TWVolatilityAverage The average volatility in the recent range
  /// @return TWVolumePerLiqAverage The average volume per liquidity in the recent range
  function getAverages(
    uint32 time,
    int24 tick,
    uint16 index,
    uint128 liquidity
  ) external view returns (uint112 TWVolatilityAverage, uint256 TWVolumePerLiqAverage);

  /// @notice Writes an dataStorage timepoint to the array
  /// @dev Writable at most once per block. Index represents the most recently written element. index must be tracked externally.
  /// @param index The index of the timepoint that was most recently written to the timepoints array
  /// @param blockTimestamp The timestamp of the new timepoint
  /// @param tick The active tick at the time of the new timepoint
  /// @param liquidity The total in-range liquidity at the time of the new timepoint
  /// @param volumePerLiquidity The gmean(volumes)/liquidity at the time of the new timepoint
  /// @return indexUpdated The new index of the most recently written element in the dataStorage array
  function write(
    uint16 index,
    uint32 blockTimestamp,
    int24 tick,
    uint128 liquidity,
    uint128 volumePerLiquidity
  ) external returns (uint16 indexUpdated);

  /// @notice Changes fee configuration for the pool
  function changeFeeConfiguration(bool zto, AdaptiveFee.Configuration calldata feeConfig) external;

  /// @notice Calculates gmean(volume/liquidity) for block
  /// @param liquidity The current in-range pool liquidity
  /// @param amount0 Total amount of swapped token0
  /// @param amount1 Total amount of swapped token1
  /// @return volumePerLiquidity gmean(volume/liquidity) capped by 100000 << 64
  function calculateVolumePerLiquidity(
    uint128 liquidity,
    int256 amount0,
    int256 amount1
  ) external pure returns (uint128 volumePerLiquidity);

  /// @return windowLength Length of window used to calculate averages
  function window() external view returns (uint32 windowLength);

  /// @notice Calculates fee based on combination of sigmoids
  /// @param time The current block.timestamp
  /// @param tick The current tick
  /// @param index The index of the timepoint that was most recently written to the timepoints array
  /// @param liquidity The current in-range pool liquidity
  /// @return feeZto The fee for ZtO swaps in hundredths of a bip, i.e. 1e-6
  /// @return feeOtz The fee for OtZ swaps in hundredths of a bip, i.e. 1e-6
  function getFees(
    uint32 time,
    int24 tick,
    uint16 index,
    uint128 liquidity
  ) external view returns (uint16 feeZto, uint16 feeOtz);
}
          

contracts/libraries/Sqrt.sol

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0;

library Sqrt {
  /// @notice Gets the square root of the absolute value of the parameter
  function sqrtAbs(int256 _x) internal pure returns (uint256 result) {
    // get abs value
    int256 mask = _x >> (256 - 1);
    uint256 x = uint256((_x ^ mask) - mask);
    if (x == 0) result = 0;
    else {
      uint256 xx = x;
      uint256 r = 1;
      if (xx >= 0x100000000000000000000000000000000) {
        xx >>= 128;
        r <<= 64;
      }
      if (xx >= 0x10000000000000000) {
        xx >>= 64;
        r <<= 32;
      }
      if (xx >= 0x100000000) {
        xx >>= 32;
        r <<= 16;
      }
      if (xx >= 0x10000) {
        xx >>= 16;
        r <<= 8;
      }
      if (xx >= 0x100) {
        xx >>= 8;
        r <<= 4;
      }
      if (xx >= 0x10) {
        xx >>= 4;
        r <<= 2;
      }
      if (xx >= 0x8) {
        r <<= 1;
      }
      r = (r + x / r) >> 1;
      r = (r + x / r) >> 1;
      r = (r + x / r) >> 1;
      r = (r + x / r) >> 1;
      r = (r + x / r) >> 1;
      r = (r + x / r) >> 1;
      r = (r + x / r) >> 1; // @dev Seven iterations should be enough.
      uint256 r1 = x / r;
      result = r < r1 ? r : r1;
    }
  }
}
          

Compiler Settings

{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"optimizer":{"runs":0,"enabled":true},"metadata":{"bytecodeHash":"none"},"libraries":{}}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_poolDeployer","internalType":"address"},{"type":"address","name":"_vaultAddress","internalType":"address"}]},{"type":"event","name":"DefaultCommunityFee","inputs":[{"type":"uint8","name":"newDefaultCommunityFee","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"FarmingAddress","inputs":[{"type":"address","name":"newFarmingAddress","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"FeeConfiguration","inputs":[{"type":"uint16","name":"alpha1","internalType":"uint16","indexed":false},{"type":"uint16","name":"alpha2","internalType":"uint16","indexed":false},{"type":"uint32","name":"beta1","internalType":"uint32","indexed":false},{"type":"uint32","name":"beta2","internalType":"uint32","indexed":false},{"type":"uint16","name":"gamma1","internalType":"uint16","indexed":false},{"type":"uint16","name":"gamma2","internalType":"uint16","indexed":false},{"type":"uint32","name":"volumeBeta","internalType":"uint32","indexed":false},{"type":"uint16","name":"volumeGamma","internalType":"uint16","indexed":false},{"type":"uint16","name":"baseFee","internalType":"uint16","indexed":false}],"anonymous":false},{"type":"event","name":"Owner","inputs":[{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Pool","inputs":[{"type":"address","name":"token0","internalType":"address","indexed":true},{"type":"address","name":"token1","internalType":"address","indexed":true},{"type":"address","name":"pool","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"VaultAddress","inputs":[{"type":"address","name":"newVaultAddress","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"alpha1","internalType":"uint16"},{"type":"uint16","name":"alpha2","internalType":"uint16"},{"type":"uint32","name":"beta1","internalType":"uint32"},{"type":"uint32","name":"beta2","internalType":"uint32"},{"type":"uint16","name":"gamma1","internalType":"uint16"},{"type":"uint16","name":"gamma2","internalType":"uint16"},{"type":"uint32","name":"volumeBeta","internalType":"uint32"},{"type":"uint16","name":"volumeGamma","internalType":"uint16"},{"type":"uint16","name":"baseFee","internalType":"uint16"}],"name":"baseFeeConfiguration","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":"pool","internalType":"address"}],"name":"createPool","inputs":[{"type":"address","name":"tokenA","internalType":"address"},{"type":"address","name":"tokenB","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"defaultCommunityFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"farmingAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"poolByPair","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"poolDeployer","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBaseFeeConfiguration","inputs":[{"type":"uint16","name":"alpha1","internalType":"uint16"},{"type":"uint16","name":"alpha2","internalType":"uint16"},{"type":"uint32","name":"beta1","internalType":"uint32"},{"type":"uint32","name":"beta2","internalType":"uint32"},{"type":"uint16","name":"gamma1","internalType":"uint16"},{"type":"uint16","name":"gamma2","internalType":"uint16"},{"type":"uint32","name":"volumeBeta","internalType":"uint32"},{"type":"uint16","name":"volumeGamma","internalType":"uint16"},{"type":"uint16","name":"baseFee","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDefaultCommunityFee","inputs":[{"type":"uint8","name":"newDefaultCommunityFee","internalType":"uint8"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFarmingAddress","inputs":[{"type":"address","name":"_farmingAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOwner","inputs":[{"type":"address","name":"_owner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setVaultAddress","inputs":[{"type":"address","name":"_vaultAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"vaultAddress","inputs":[]}]
              

Contract Creation Code

0x6101c0604052610b5460a0819052612ee060c05261016860e05261ea6061010052603b6101205261213461014052600061016052600a6101805260646101a0526003805461ffff191690911763ffff00001916632ee000001763ffffffff60201b1916650168000000001763ffffffff60401b191669ea6000000000000000001761ffff60601b19166c3b0000000000000000000000001761ffff60701b191661084d60721b1765ffffffffffff60801b1916600560a11b1761ffff60b01b1916601960b21b1790553480156100d457600080fd5b506040516138aa3803806138aa8339810160408190526100f391610182565b600080546001600160a01b03191633908117825560405190917fa5e220c2c27d986cc8efeafa8f34ba6ea6bf96a34e146b29b6bdd8587771b13091a260609190911b6001600160601b031916608052600280546001600160a01b0319166001600160a01b039092169190911790556101b4565b80516001600160a01b038116811461017d57600080fd5b919050565b60008060408385031215610194578182fd5b61019d83610166565b91506101ab60208401610166565b90509250929050565b60805160601c6136cf6101db6000398061023d52806108fb5280610a2b52506136cf6000f3fe608060405234801561001057600080fd5b50600436106100af5760003560e01c806313af4035146100b45780632f8a39dd146100c95780633119049a146100e7578063371e3521146100fc578063430bf08a1461010f5780635d6d7e931461011757806385535cc51461012a5780638a2ade581461013d5780638da5cb5b146101455780639832853a1461014d578063b001f6181461016a578063d9a641e11461017d578063e343361514610190575b600080fd5b6100c76100c2366004610afc565b6101a3565b005b6100d161022b565b6040516100de9190610e44565b60405180910390f35b6100ef61023b565b6040516100de9190610c80565b6100c761010a366004610c1a565b61025f565b6100ef6102f6565b6100c7610125366004610b73565b610305565b6100c7610138366004610afc565b61059b565b6100ef610623565b6100ef610632565b610155610641565b6040516100de99989796959493929190610def565b6100c7610178366004610afc565b6106a1565b6100ef61018b366004610b3b565b610729565b6100ef61019e366004610b3b565b61074f565b6000546001600160a01b031633146101ba57600080fd5b6000546001600160a01b03828116911614156101d557600080fd5b6040516001600160a01b038216907fa5e220c2c27d986cc8efeafa8f34ba6ea6bf96a34e146b29b6bdd8587771b13090600090a2600080546001600160a01b0319166001600160a01b0392909216919091179055565b600054600160a01b900460ff1681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b0316331461027657600080fd5b60fa60ff8216111561028757600080fd5b60005460ff828116600160a01b9092041614156102a357600080fd5b6000805460ff60a01b1916600160a01b60ff8416021790556040517f88cb5103fd9d88d417e72dc496030c71c65d1500548a9e9530e7d812b6a35558906102eb908390610e44565b60405180910390a150565b6002546001600160a01b031681565b6000546001600160a01b0316331461031c57600080fd5b61ffff898116898216018282160111156103515760405162461bcd60e51b815260040161034890610dc5565b60405180910390fd5b61ffff851615801590610367575061ffff841615155b8015610376575061ffff821615155b6103925760405162461bcd60e51b815260040161034890610d99565b6040518061012001604052808a61ffff1681526020018961ffff1681526020018863ffffffff1681526020018763ffffffff1681526020018661ffff1681526020018561ffff1681526020018463ffffffff1681526020018361ffff1681526020018261ffff16815250600360008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a81548161ffff021916908361ffff16021790555060408201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600c6101000a81548161ffff021916908361ffff16021790555060a082015181600001600e6101000a81548161ffff021916908361ffff16021790555060c08201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060e08201518160000160146101000a81548161ffff021916908361ffff1602179055506101008201518160000160166101000a81548161ffff021916908361ffff1602179055509050507f4035ab409f15e202f9f114632e1fb14a0552325955722be18503403e7f98730c89898989898989898960405161058899989796959493929190610def565b60405180910390a1505050505050505050565b6000546001600160a01b031633146105b257600080fd5b6002546001600160a01b03828116911614156105cd57600080fd5b6040516001600160a01b038216907fb9c265ae4414f501736ec5d4961edc3309e4385eb2ff3feeecb30fb36621dd8390600090a2600280546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031681565b6000546001600160a01b031681565b60035461ffff8082169162010000810482169163ffffffff600160201b8304811692600160401b8104821692600160601b8204811692600160701b8304821692600160801b810490911691600160a01b8204811691600160b01b90041689565b6000546001600160a01b031633146106b857600080fd5b6001546001600160a01b03828116911614156106d357600080fd5b6040516001600160a01b038216907f56b9e8342f530796ceed0d5529abdcdeae6e4f2ac1dc456ceb73bbda898e0cd390600090a2600180546001600160a01b0319166001600160a01b0392909216919091179055565b60046020908152600092835260408084209091529082529020546001600160a01b031681565b6000816001600160a01b0316836001600160a01b0316141561077057600080fd5b600080836001600160a01b0316856001600160a01b031610610793578385610796565b84845b90925090506001600160a01b0382166107ae57600080fd5b6001600160a01b038281166000908152600460209081526040808320858516845290915290205416156107e057600080fd5b60006107ec8383610a27565b6040516107f890610ac4565b6108029190610c80565b604051809103906000f08015801561081e573d6000803e3d6000fd5b50604051635253311160e01b81529091506001600160a01b0382169063525331119061085290600190600390600401610cd9565b600060405180830381600087803b15801561086c57600080fd5b505af1158015610880573d6000803e3d6000fd5b5050604051635253311160e01b81526001600160a01b0384169250635253311191506108b490600090600390600401610cd9565b600060405180830381600087803b1580156108ce57600080fd5b505af11580156108e2573d6000803e3d6000fd5b5050604051637ec15b9d60e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063fd82b73a9150610938908490309088908890600401610cae565b602060405180830381600087803b15801561095257600080fd5b505af1158015610966573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098a9190610b1f565b6001600160a01b03808516600081815260046020818152604080842089871680865290835281852080549789166001600160a01b031998891681179091559383528185208686529092529283902080549095169091179093555192965090917f91ccaa7a278130b65168c3a0c8d3bcae84cf5e43704342bd3ec0b59e59c036db90610a16908890610c80565b60405180910390a350505092915050565b60007f00000000000000000000000000000000000000000000000000000000000000008383604051602001610a5d929190610c94565b60408051601f19818403018152908290528051602091820120610aa5939290917f6c1bebd370ba84753516bc1393c0d0a6c645856da55f5393ac8ab3d6dbc861d39101610c4d565b60408051601f1981840301815291905280516020909101209392505050565b61285880610e6b83390190565b803561ffff81168114610ae357600080fd5b919050565b803563ffffffff81168114610ae357600080fd5b600060208284031215610b0d578081fd5b8135610b1881610e52565b9392505050565b600060208284031215610b30578081fd5b8151610b1881610e52565b60008060408385031215610b4d578081fd5b8235610b5881610e52565b91506020830135610b6881610e52565b809150509250929050565b60008060008060008060008060006101208a8c031215610b91578485fd5b610b9a8a610ad1565b9850610ba860208b01610ad1565b9750610bb660408b01610ae8565b9650610bc460608b01610ae8565b9550610bd260808b01610ad1565b9450610be060a08b01610ad1565b9350610bee60c08b01610ae8565b9250610bfc60e08b01610ad1565b9150610c0b6101008b01610ad1565b90509295985092959850929598565b600060208284031215610c2b578081fd5b813560ff81168114610b18578182fd5b61ffff169052565b63ffffffff169052565b6001600160f81b0319815260609390931b6001600160601b03191660018401526015830191909152603582015260550190565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03948516815292841660208401529083166040830152909116606082015260800190565b8215158152815461014082019061ffff610cf860208501828416610c3b565b610d0a60408501828460101c16610c3b565b63ffffffff610d2160608601828560201c16610c43565b610d3360808601828560401c16610c43565b610d4560a08601838560601c16610c3b565b610d5760c08601838560701c16610c3b565b610d6960e08601828560801c16610c43565b50610d7d6101008501828460a01c16610c3b565b610d906101208501828460b01c16610c3b565b50509392505050565b602080825260129082015271047616d6d6173206d757374206265203e20360741b604082015260600190565b60208082526010908201526f13585e0819995948195e18d95959195960821b604082015260600190565b61ffff998a168152978916602089015263ffffffff96871660408901529486166060880152928716608087015290861660a086015290921660c084015290831660e08301529091166101008201526101200190565b60ff91909116815260200190565b6001600160a01b0381168114610e6757600080fd5b5056fe60c06040523480156200001157600080fd5b506040516200285838038062002858833981016040819052620000349162000051565b33606090811b60a0521b6001600160601b03191660805262000081565b60006020828403121562000063578081fd5b81516001600160a01b03811681146200007a578182fd5b9392505050565b60805160601c60a05160601c61278f620000c960003980610455528061047e52508061021252806102dd52806103fd52806107af528061097a52806109ed525061278f6000f3fe608060405234801561001057600080fd5b50600436106100a45760003560e01c806314c54079146100a95780631dd486f2146100d557806336e52fee146100f5578063461645bf14610115578063475fb80c1461012a578063525331111461013f57806374eceae614610152578063824e8e871461017857806390577ef614610195578063a80b96a11461019d578063bc2e0181146101be578063fd31e988146101df575b600080fd5b6100bc6100b7366004612148565b610202565b6040516100cc9493929190612412565b60405180910390f35b6100e86100e3366004611f5c565b6102d0565b6040516100cc91906124f8565b610108610103366004611f0e565b610333565b6040516100cc91906124e4565b61011d6103eb565b6040516100cc9190612571565b61013d6101383660046120bd565b6103f2565b005b61013d61014d366004611ec9565b61044a565b610165610160366004611fc4565b610664565b6040516100cc97969594939291906123b9565b6101806106dd565b6040516100cc9998979695949392919061251c565b61018061073f565b6101b06101ab3660046120f1565b6107a1565b6040516100cc929190612507565b6101d16101cc3660046120f1565b61096c565b6040516100cc9291906124cb565b6101f26101ed366004611fdc565b6109dd565b6040516100cc949392919061221c565b6000808080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146102585760405162461bcd60e51b815260040161024f90612470565b60405180910390fd5b6000600187018161ffff821662010000811061027057fe5b600202015460ff1615610281578091505b6000610292818d8d8d8d888e610a4c565b60408101516060820151608083015160c090930151919f909e506001600160581b039092169c506001600160901b03169a5098505050505050505050565b6000336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461031a5760405162461bcd60e51b815260040161024f90612470565b6103296000878787878761101b565b9695505050505050565b60008061033f836112c9565b610348856112c9565b0290506000600160c01b821061038d576000866001600160801b031611610370576001610372565b855b6001600160801b03166000198161038557fe5b0490506103c0565b6000866001600160801b0316116103a55760016103a7565b855b6001600160801b0316604083901b816103bc57fe5b0490505b610c3560451b81106103db57610c3560451b925050506103e4565b91506103e49050565b9392505050565b6201518090565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461043a5760405162461bcd60e51b815260040161024f90612470565b61044660008383611419565b5050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061052257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156104d557600080fd5b505afa1580156104e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050d9190611ea2565b6001600160a01b0316336001600160a01b0316145b61052b57600080fd5b61ffff61054061012083016101008401611f40565b61ffff166105546040840160208501611f40565b61ffff166105656020850185611f40565b61ffff16010111156105895760405162461bcd60e51b815260040161024f906124a1565b61059960a0820160808301611f40565b61ffff16158015906105bd57506105b660c0820160a08301611f40565b61ffff1615155b80156105dc57506105d5610100820160e08301611f40565b61ffff1615155b6105f85760405162461bcd60e51b815260040161024f90612444565b811561061557806202000061060d82826125a2565b905050610627565b806202000161062482826125a2565b50505b7ffde738fae78aad21a8ad5935e1ff28b89cea38834539a91ae210ba7a22c067a582826040516106589291906122bf565b60405180910390a15050565b60008162010000811061067657600080fd5b600290810291909101805460019091015460ff82169350610100820463ffffffff1692600160281b830460060b92600160601b90046001600160a01b0316916001600160581b03811691600160581b8204900b90600160701b90046001600160901b031687565b620200005461ffff8082169162010000810482169163ffffffff600160201b8304811692600160401b8104821692600160601b8204811692600160701b8304821692600160801b810490911691600160a01b8204811691600160b01b90041689565b620200015461ffff8082169162010000810482169163ffffffff600160201b8304811692600160401b8104821692600160601b8204811692600160701b8304821692600160801b810490911691600160a01b8204811691600160b01b90041689565b600080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107ec5760405162461bcd60e51b815260040161024f90612470565b6000806107fc8189898989611478565b915091506108b2600f836001600160581b03168161081657fe5b6040805161012081018252620200005461ffff80821683526201000082048116602084015263ffffffff600160201b8304811694840194909452600160401b820484166060840152600160601b820481166080840152600160701b8204811660a0840152600160801b820490931660c0830152600160a01b8104831660e0830152600160b01b90049091166101008201529190049083906115f7565b935061095f600f6001600160581b0384166040805161012081018252620200015461ffff80821683526201000082048116602084015263ffffffff600160201b8304811694840194909452600160401b820484166060840152600160601b820481166080840152600160701b8204811660a0840152600160801b820490931660c0830152600160a01b8104831660e0830152600160b01b90049091166101008201529190049083906115f7565b9250505094509492505050565b600080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109b75760405162461bcd60e51b815260040161024f90612470565b6109c5600087878787611478565b6001600160581b039091169250905094509492505050565b6060808080336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a2a5760405162461bcd60e51b815260040161024f90612470565b610a3960008a8a8a8a8a611689565b929c919b50995090975095505050505050565b610a54611e22565b85870363ffffffff87161580610a915750610a91898661ffff16620100008110610a7a57fe5b6002020154610100900463ffffffff16828a6118bd565b15610c14576000898661ffff16620100008110610aaa57fe5b6040805160e081018252600292830293909301805460ff811615158552610100810463ffffffff90811660208701819052600160281b8304600690810b810b900b94870194909452600160601b9091046001600160a01b031660608601526001909101546001600160581b0381166080860152600160581b8104840b840b90930b60a0850152600160701b9092046001600160901b031660c084015291925083161415610b5a5791506110109050565b6000610b738b8b8a8a8a876020015188604001516118e6565b90508761ffff88811690881614610bf957610b8c611e22565b60008d60018b0361ffff16620100008110610ba357fe5b60020201805463ffffffff610100820481166020808701829052600160281b909304600690810b810b810b6040808901829052948b0151948b0151959650919093039091169203900b81610bf357fe5b05925050505b610c0983858b848a876000611a50565b945050505050611010565b610c29898561ffff16620100008110610a7a57fe5b610c60576040805162461bcd60e51b815260206004820152600360248201526213d31160ea1b604482015290519081900360640190fd5b600080610c708b8b858a8a611b54565b6040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900460060b60060b60060b815260200160008201600c9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160581b03166001600160581b03166001600160581b0316815260200160018201600b9054906101000a900460020b60020b60020b815260200160018201600e9054906101000a90046001600160901b03166001600160901b03166001600160901b03168152505091506040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900460060b60060b60060b815260200160008201600c9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160581b03166001600160581b03166001600160581b0316815260200160018201600b9054906101000a900460020b60020b60020b815260200160018201600e9054906101000a90046001600160901b03166001600160901b03166001600160901b0316815250509150806020015163ffffffff168363ffffffff161415610ebc579250611010915050565b816020015163ffffffff168363ffffffff161461100b5760008260200151826020015103905060008360200151850390508063ffffffff168263ffffffff16856040015185604001510360060b81610f1057fe5b0502846040018181510191509060060b908160060b815250508163ffffffff168163ffffffff1685606001518560600151036001600160a01b03160281610f5357fe5b0484606001818151019150906001600160a01b031690816001600160a01b0316815250508063ffffffff168263ffffffff1685608001518560800151036001600160581b031681610fa057fe5b040284608001818151019150906001600160581b031690816001600160581b0316815250508063ffffffff168263ffffffff168560c001518560c00151036001600160901b031681610fee57fe5b60c0870180516001600160901b0393909204939093020116905250505b509150505b979650505050505050565b600080878761ffff1662010000811061103057fe5b60020201805490915063ffffffff8781166101009092041614156110575786915050610329565b6040805160e081018252825460ff811615158252610100810463ffffffff166020830152600160281b8104600690810b810b900b92820192909252600160601b9091046001600160a01b031660608201526001808301546001600160581b0381166080840152600160581b8104600290810b810b900b60a0840152600160701b90046001600160901b031660c08301528801925060008961ffff85166201000081106110ff57fe5b600202015460ff161561110f5750825b60006111288b8a8a8d86886020015189604001516118e6565b90508761ffff8b8116908416146111995760008c60018d0361ffff1662010000811061115057fe5b6002020180546020870151604088015192935063ffffffff6101008304811693600160281b909304600690810b939285900390911691839003900b8161119257fe5b0593505050505b6111a8848b8b848c878d611a50565b8c8761ffff166201000081106111ba57fe5b825160029182029290920180546020850151604086015160608701516001600160a01b0316600160601b026001600160601b0360069290920b66ffffffffffffff16600160281b02600160281b600160601b031963ffffffff9094166101000264ffffffff001998151560ff1990961695909517979097169390931791909116949094179390931692909217825560808301516001909201805460a085015160c0909501516001600160901b0316600160701b026001600160701b039590930b62ffffff16600160581b0262ffffff60581b196001600160581b039095166001600160581b03199092169190911793909316929092179290921691909117905550505050509695505050505050565b600060ff82901d808318819003806112e45760009250611412565b806001600160801b82106112fd5760809190911c9060401b5b600160401b82106113135760409190911c9060201b5b600160201b82106113295760209190911c9060101b5b62010000821061133e5760109190911c9060081b5b61010082106113525760089190911c9060041b5b601082106113655760049190911c9060021b5b600882106113715760011b5b600181848161137c57fe5b048201901c9050600181848161138e57fe5b048201901c905060018184816113a057fe5b048201901c905060018184816113b257fe5b048201901c905060018184816113c457fe5b048201901c905060018184816113d657fe5b048201901c905060018184816113e857fe5b048201901c905060008184816113fa57fe5b04905080821061140a578061140c565b815b95505050505b5050919050565b825460ff161561142857600080fd5b825463ffffffff9290921661010002600160ff19909316831764ffffffff0019161783559101805462ffffff60581b1916600160581b62ffffff60029490940b9390931692909202919091179055565b6000808087600186018161ffff821662010000811061149357fe5b600202015460ff16156114bc57898161ffff166201000081106114b257fe5b6002020191508092505b60006114ce8b8b60008c8c898d610a4c565b8354909150610100900463ffffffff166114ef816201517f198d018d6118bd565b156115575760006115088d8d620151808e8e8b8f610a4c565b90506201518063ffffffff1681608001518460800151036001600160581b03168161152f57fe5b0460398260c001518560c00151036001600160901b0316901c975097505050505050506115ed565b8063ffffffff168b63ffffffff16146115e75760008460010160009054906101000a90046001600160581b03169050600085600101600e9054906101000a90046001600160901b03169050828d0363ffffffff16828560800151036001600160581b0316816115c257fe5b046039828660c00151036001600160901b0316901c98509850505050505050506115ed565b50505050505b9550959350505050565b600080611621856001600160581b03168460a001518560200151866060015163ffffffff16611c5b565b611648866001600160581b031685608001518660000151876040015163ffffffff16611c5b565b01905061ffff81111561165a575061ffff5b611674848460e00151838660c0015163ffffffff16611c5b565b83610100015161ffff16019150509392505050565b60608060608087516001600160401b03811180156116a657600080fd5b506040519080825280602002602001820160405280156116d0578160200160208202803683370190505b50935087516001600160401b03811180156116ea57600080fd5b50604051908082528060200260200182016040528015611714578160200160208202803683370190505b50925087516001600160401b038111801561172e57600080fd5b50604051908082528060200260200182016040528015611758578160200160208202803683370190505b50915087516001600160401b038111801561177257600080fd5b5060405190808252806020026020018201604052801561179c578160200160208202803683370190505b5090506000600187018b61ffff82166201000081106117b757fe5b600202015460ff16156117c8578091505b6117d0611e22565b60005b8b518110156118ac576117fe8e8e8e84815181106117ed57fe5b60200260200101518e8e898f610a4c565b91508160400151826060015183608001518460c00151816001600160581b03169150806001600160901b031690508b858151811061183857fe5b602002602001018b868151811061184b57fe5b602002602001018b878151811061185e57fe5b602002602001018b888151811061187157fe5b60209081029190910101939093526001600160701b039093169091526001600160a01b039092169052600691820b90910b90526001016117d3565b505050509650965096509692505050565b63ffffffff8082168482168110918416118114156103e457505063ffffffff9081169116111590565b600080888561ffff166201000081106118fb57fe5b6002020154610100900463ffffffff16905060008961ffff871662010000811061192157fe5b6002020154600160281b900460060b9050611943826201517f198b018b6118bd565b15611a095761195885620151808b038b6118bd565b156119c65760018703965060008a8861ffff1662010000811061197757fe5b60020201805490915060ff16611990578860020b6119bb565b805463ffffffff6101008204811688031690600160281b9004600690810b8703900b816119b957fe5b055b60060b935050611a04565b60006119db8b8b620151808c8c8c6000610a4c565b9050620151808a87030163ffffffff168160400151860360060b816119fc57fe5b0560060b9350505b611a43565b8163ffffffff168563ffffffff1614611a385781850363ffffffff1681850360060b81611a3257fe5b05611a3d565b8760020b5b60060b92505b5050979650505050505050565b611a58611e22565b60208801805160018a5263ffffffff89811690925260408a018051918a0392831660028a900b02909101600690810b900b90526001600160801b038516611aa0576001611aa2565b845b6001600160801b031663ffffffff60801b608083901b1681611ac057fe5b0489606001818151019150906001600160a01b031690816001600160a01b031681525050611b078163ffffffff168760020b8960020b8c60a0015160020b8860020b611d05565b60808a018051919091016001600160581b031690525050600291820b90910b60a087015260c0860180516001600160801b03929092169091016001600160901b0316905250929392505050565b60008061ffff8084169082908616821115611b7857620100008661ffff1601611b7e565b8561ffff165b905081810160011c5b898161ffff16620100008110611b9957fe5b60020201805490955060ff811690610100900463ffffffff168115611c4657611bc3818b8d6118bd565b15611c3a578b8360010161ffff16620100008110611bdd57fe5b60020201805490965060ff811690610100900463ffffffff168115611c2357611c078c828f6118bd565b15611c1857505050505050506115ed565b846001019650611c33565b508796506115ed95505050505050565b5050611c41565b6001830393505b611c4d565b8260010194505b50505081810160011c611b87565b600081851115611cb55781850394508361ffff166006028510611c83575061ffff8216611cfd565b600861ffff85160a6000611c98878784611d5a565b9050808201818661ffff160281611cab57fe5b0492505050611cfd565b93810393600661ffff8516028510611ccf57506000611cfd565b600861ffff85160a6000611ce4878784611d5a565b8201905080828661ffff160281611cf757fe5b04925050505b949350505050565b6000828203858503038386038702600180890189026002808b02929092018102916006818c0a81029180870a8502868802850283020190860a8d029091020181611d4b57fe5b059a9950505050505050505050565b808361ffff84168281611d6957fe5b049250828102820191508361ffff168381611d8057fe5b0492508402600281840204820191508361ffff168381611d9c57fe5b0492508402600681840204820191508361ffff168381611db857fe5b0492508402601881840204820191508361ffff168381611dd457fe5b0492508402607881840204820191508361ffff168381611df057fe5b04925084026102d08184020491909101908402619d80818602046113b061ffff86168302040182019150509392505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b8035600281900b8114611e7057600080fd5b919050565b80356001600160801b0381168114611e7057600080fd5b8035611e708161275d565b8035611e7081612770565b600060208284031215611eb3578081fd5b81516001600160a01b03811681146103e4578182fd5b600080828403610140811215611edd578182fd5b83358015158114611eec578283fd5b9250610120601f1982011215611f00578182fd5b506020830190509250929050565b600080600060608486031215611f22578081fd5b611f2b84611e75565b95602085013595506040909401359392505050565b600060208284031215611f51578081fd5b81356103e48161275d565b600080600080600060a08688031215611f73578081fd5b8535611f7e8161275d565b94506020860135611f8e81612770565b9350611f9c60408701611e5e565b9250611faa60608701611e75565b9150611fb860808701611e75565b90509295509295909350565b600060208284031215611fd5578081fd5b5035919050565b600080600080600060a08688031215611ff3578081fd5b8535611ffe81612770565b94506020868101356001600160401b038082111561201a578384fd5b818901915089601f83011261202d578384fd5b81358181111561203957fe5b8381026040518582820101818110858211171561205257fe5b604052828152858101935084860182860187018e1015612070578788fd5b8795505b838610156120995761208581611e97565b855260019590950194938601938601612074565b508099505050505050506120af60408701611e5e565b9250611faa60608701611e8c565b600080604083850312156120cf578182fd5b82356120da81612770565b91506120e860208401611e5e565b90509250929050565b60008060008060808587031215612106578384fd5b843561211181612770565b935061211f60208601611e5e565b9250604085013561212f8161275d565b915061213d60608601611e75565b905092959194509250565b600080600080600060a0868803121561215f578081fd5b853561216a81612770565b9450602086013561217a81612770565b935061218860408701611e5e565b92506060860135611faa8161275d565b6000815180845260208085019450808401835b838110156121d05781516001600160701b0316875295820195908201906001016121ab565b509495945050505050565b6000815180845260208085019450808401835b838110156121d0578151875295820195908201906001016121ee565b61ffff169052565b63ffffffff169052565b6080808252855190820181905260009060209060a0840190828901845b8281101561225857815160060b84529284019290840190600101612239565b50505083810382850152865180825287830191830190845b818110156122955783516001600160a01b031683529284019291840191600101612270565b505084810360408601526122a98188612198565b92505050828103606084015261101081856121db565b821515815261014081016122de602083016122d985611e8c565b61220a565b6122ea60208401611e8c565b6122f7604084018261220a565b5061230460408401611e97565b6123116060840182612212565b5061231e60608401611e97565b61232b6080840182612212565b5061233860808401611e8c565b61234560a084018261220a565b5061235260a08401611e8c565b61235f60c084018261220a565b5061236c60c08401611e97565b61237960e0840182612212565b5061238660e08401611e8c565b6101006123958185018361220a565b6123a0818601611e8c565b9150506123b161012084018261220a565b509392505050565b961515875263ffffffff95909516602087015260069390930b60408601526001600160a01b039190911660608501526001600160581b0316608084015260020b60a08301526001600160901b031660c082015260e00190565b60069490940b84526001600160a01b039290921660208401526001600160701b03166040830152606082015260800190565b602080825260129082015271047616d6d6173206d757374206265203e20360741b604082015260600190565b6020808252601790820152766f6e6c7920706f6f6c2063616e2063616c6c207468697360481b604082015260600190565b60208082526010908201526f13585e0819995948195e18d95959195960821b604082015260600190565b6001600160701b03929092168252602082015260400190565b6001600160801b0391909116815260200190565b61ffff91909116815260200190565b61ffff92831681529116602082015260400190565b61ffff998a168152978916602089015263ffffffff96871660408901529486166060880152928716608087015290861660a086015290921660c084015290831660e08301529091166101008201526101200190565b63ffffffff91909116815260200190565b6000813561258f8161275d565b92915050565b6000813561258f81612770565b81356125ad8161275d565b815461ffff191661ffff919091161780825560208301356125cd8161275d565b63ffff00008160101b1663ffff000019831617835550506125f96125f360408401612595565b82612717565b61260e61260860608401612595565b8261273a565b61262361261d60808401612582565b82612678565b61263861263260a08401612582565b82612697565b61264d61264760c08401612595565b826126b6565b61266261265c60e08401612582565b826126d9565b6104466126726101008401612582565b826126f8565b805461ffff60601b191660609290921b61ffff60601b16919091179055565b805461ffff60701b191660709290921b61ffff60701b16919091179055565b805463ffffffff60801b191660809290921b63ffffffff60801b16919091179055565b805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b805461ffff60b01b191660b09290921b61ffff60b01b16919091179055565b805463ffffffff60201b191660209290921b63ffffffff60201b16919091179055565b805463ffffffff60401b191660409290921b63ffffffff60401b16919091179055565b61ffff8116811461276d57600080fd5b50565b63ffffffff8116811461276d57600080fdfea164736f6c6343000706000aa164736f6c6343000706000a0000000000000000000000005822a45b05d08028baa3d19626870076d26bc460000000000000000000000000be56e9aa7792b2f1f4132631b7a0e1927090d78a

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106100af5760003560e01c806313af4035146100b45780632f8a39dd146100c95780633119049a146100e7578063371e3521146100fc578063430bf08a1461010f5780635d6d7e931461011757806385535cc51461012a5780638a2ade581461013d5780638da5cb5b146101455780639832853a1461014d578063b001f6181461016a578063d9a641e11461017d578063e343361514610190575b600080fd5b6100c76100c2366004610afc565b6101a3565b005b6100d161022b565b6040516100de9190610e44565b60405180910390f35b6100ef61023b565b6040516100de9190610c80565b6100c761010a366004610c1a565b61025f565b6100ef6102f6565b6100c7610125366004610b73565b610305565b6100c7610138366004610afc565b61059b565b6100ef610623565b6100ef610632565b610155610641565b6040516100de99989796959493929190610def565b6100c7610178366004610afc565b6106a1565b6100ef61018b366004610b3b565b610729565b6100ef61019e366004610b3b565b61074f565b6000546001600160a01b031633146101ba57600080fd5b6000546001600160a01b03828116911614156101d557600080fd5b6040516001600160a01b038216907fa5e220c2c27d986cc8efeafa8f34ba6ea6bf96a34e146b29b6bdd8587771b13090600090a2600080546001600160a01b0319166001600160a01b0392909216919091179055565b600054600160a01b900460ff1681565b7f0000000000000000000000005822a45b05d08028baa3d19626870076d26bc46081565b6000546001600160a01b0316331461027657600080fd5b60fa60ff8216111561028757600080fd5b60005460ff828116600160a01b9092041614156102a357600080fd5b6000805460ff60a01b1916600160a01b60ff8416021790556040517f88cb5103fd9d88d417e72dc496030c71c65d1500548a9e9530e7d812b6a35558906102eb908390610e44565b60405180910390a150565b6002546001600160a01b031681565b6000546001600160a01b0316331461031c57600080fd5b61ffff898116898216018282160111156103515760405162461bcd60e51b815260040161034890610dc5565b60405180910390fd5b61ffff851615801590610367575061ffff841615155b8015610376575061ffff821615155b6103925760405162461bcd60e51b815260040161034890610d99565b6040518061012001604052808a61ffff1681526020018961ffff1681526020018863ffffffff1681526020018763ffffffff1681526020018661ffff1681526020018561ffff1681526020018463ffffffff1681526020018361ffff1681526020018261ffff16815250600360008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a81548161ffff021916908361ffff16021790555060408201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600c6101000a81548161ffff021916908361ffff16021790555060a082015181600001600e6101000a81548161ffff021916908361ffff16021790555060c08201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060e08201518160000160146101000a81548161ffff021916908361ffff1602179055506101008201518160000160166101000a81548161ffff021916908361ffff1602179055509050507f4035ab409f15e202f9f114632e1fb14a0552325955722be18503403e7f98730c89898989898989898960405161058899989796959493929190610def565b60405180910390a1505050505050505050565b6000546001600160a01b031633146105b257600080fd5b6002546001600160a01b03828116911614156105cd57600080fd5b6040516001600160a01b038216907fb9c265ae4414f501736ec5d4961edc3309e4385eb2ff3feeecb30fb36621dd8390600090a2600280546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031681565b6000546001600160a01b031681565b60035461ffff8082169162010000810482169163ffffffff600160201b8304811692600160401b8104821692600160601b8204811692600160701b8304821692600160801b810490911691600160a01b8204811691600160b01b90041689565b6000546001600160a01b031633146106b857600080fd5b6001546001600160a01b03828116911614156106d357600080fd5b6040516001600160a01b038216907f56b9e8342f530796ceed0d5529abdcdeae6e4f2ac1dc456ceb73bbda898e0cd390600090a2600180546001600160a01b0319166001600160a01b0392909216919091179055565b60046020908152600092835260408084209091529082529020546001600160a01b031681565b6000816001600160a01b0316836001600160a01b0316141561077057600080fd5b600080836001600160a01b0316856001600160a01b031610610793578385610796565b84845b90925090506001600160a01b0382166107ae57600080fd5b6001600160a01b038281166000908152600460209081526040808320858516845290915290205416156107e057600080fd5b60006107ec8383610a27565b6040516107f890610ac4565b6108029190610c80565b604051809103906000f08015801561081e573d6000803e3d6000fd5b50604051635253311160e01b81529091506001600160a01b0382169063525331119061085290600190600390600401610cd9565b600060405180830381600087803b15801561086c57600080fd5b505af1158015610880573d6000803e3d6000fd5b5050604051635253311160e01b81526001600160a01b0384169250635253311191506108b490600090600390600401610cd9565b600060405180830381600087803b1580156108ce57600080fd5b505af11580156108e2573d6000803e3d6000fd5b5050604051637ec15b9d60e11b81526001600160a01b037f0000000000000000000000005822a45b05d08028baa3d19626870076d26bc46016925063fd82b73a9150610938908490309088908890600401610cae565b602060405180830381600087803b15801561095257600080fd5b505af1158015610966573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098a9190610b1f565b6001600160a01b03808516600081815260046020818152604080842089871680865290835281852080549789166001600160a01b031998891681179091559383528185208686529092529283902080549095169091179093555192965090917f91ccaa7a278130b65168c3a0c8d3bcae84cf5e43704342bd3ec0b59e59c036db90610a16908890610c80565b60405180910390a350505092915050565b60007f0000000000000000000000005822a45b05d08028baa3d19626870076d26bc4608383604051602001610a5d929190610c94565b60408051601f19818403018152908290528051602091820120610aa5939290917f6c1bebd370ba84753516bc1393c0d0a6c645856da55f5393ac8ab3d6dbc861d39101610c4d565b60408051601f1981840301815291905280516020909101209392505050565b61285880610e6b83390190565b803561ffff81168114610ae357600080fd5b919050565b803563ffffffff81168114610ae357600080fd5b600060208284031215610b0d578081fd5b8135610b1881610e52565b9392505050565b600060208284031215610b30578081fd5b8151610b1881610e52565b60008060408385031215610b4d578081fd5b8235610b5881610e52565b91506020830135610b6881610e52565b809150509250929050565b60008060008060008060008060006101208a8c031215610b91578485fd5b610b9a8a610ad1565b9850610ba860208b01610ad1565b9750610bb660408b01610ae8565b9650610bc460608b01610ae8565b9550610bd260808b01610ad1565b9450610be060a08b01610ad1565b9350610bee60c08b01610ae8565b9250610bfc60e08b01610ad1565b9150610c0b6101008b01610ad1565b90509295985092959850929598565b600060208284031215610c2b578081fd5b813560ff81168114610b18578182fd5b61ffff169052565b63ffffffff169052565b6001600160f81b0319815260609390931b6001600160601b03191660018401526015830191909152603582015260550190565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03948516815292841660208401529083166040830152909116606082015260800190565b8215158152815461014082019061ffff610cf860208501828416610c3b565b610d0a60408501828460101c16610c3b565b63ffffffff610d2160608601828560201c16610c43565b610d3360808601828560401c16610c43565b610d4560a08601838560601c16610c3b565b610d5760c08601838560701c16610c3b565b610d6960e08601828560801c16610c43565b50610d7d6101008501828460a01c16610c3b565b610d906101208501828460b01c16610c3b565b50509392505050565b602080825260129082015271047616d6d6173206d757374206265203e20360741b604082015260600190565b60208082526010908201526f13585e0819995948195e18d95959195960821b604082015260600190565b61ffff998a168152978916602089015263ffffffff96871660408901529486166060880152928716608087015290861660a086015290921660c084015290831660e08301529091166101008201526101200190565b60ff91909116815260200190565b6001600160a01b0381168114610e6757600080fd5b5056fe60c06040523480156200001157600080fd5b506040516200285838038062002858833981016040819052620000349162000051565b33606090811b60a0521b6001600160601b03191660805262000081565b60006020828403121562000063578081fd5b81516001600160a01b03811681146200007a578182fd5b9392505050565b60805160601c60a05160601c61278f620000c960003980610455528061047e52508061021252806102dd52806103fd52806107af528061097a52806109ed525061278f6000f3fe608060405234801561001057600080fd5b50600436106100a45760003560e01c806314c54079146100a95780631dd486f2146100d557806336e52fee146100f5578063461645bf14610115578063475fb80c1461012a578063525331111461013f57806374eceae614610152578063824e8e871461017857806390577ef614610195578063a80b96a11461019d578063bc2e0181146101be578063fd31e988146101df575b600080fd5b6100bc6100b7366004612148565b610202565b6040516100cc9493929190612412565b60405180910390f35b6100e86100e3366004611f5c565b6102d0565b6040516100cc91906124f8565b610108610103366004611f0e565b610333565b6040516100cc91906124e4565b61011d6103eb565b6040516100cc9190612571565b61013d6101383660046120bd565b6103f2565b005b61013d61014d366004611ec9565b61044a565b610165610160366004611fc4565b610664565b6040516100cc97969594939291906123b9565b6101806106dd565b6040516100cc9998979695949392919061251c565b61018061073f565b6101b06101ab3660046120f1565b6107a1565b6040516100cc929190612507565b6101d16101cc3660046120f1565b61096c565b6040516100cc9291906124cb565b6101f26101ed366004611fdc565b6109dd565b6040516100cc949392919061221c565b6000808080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146102585760405162461bcd60e51b815260040161024f90612470565b60405180910390fd5b6000600187018161ffff821662010000811061027057fe5b600202015460ff1615610281578091505b6000610292818d8d8d8d888e610a4c565b60408101516060820151608083015160c090930151919f909e506001600160581b039092169c506001600160901b03169a5098505050505050505050565b6000336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461031a5760405162461bcd60e51b815260040161024f90612470565b6103296000878787878761101b565b9695505050505050565b60008061033f836112c9565b610348856112c9565b0290506000600160c01b821061038d576000866001600160801b031611610370576001610372565b855b6001600160801b03166000198161038557fe5b0490506103c0565b6000866001600160801b0316116103a55760016103a7565b855b6001600160801b0316604083901b816103bc57fe5b0490505b610c3560451b81106103db57610c3560451b925050506103e4565b91506103e49050565b9392505050565b6201518090565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461043a5760405162461bcd60e51b815260040161024f90612470565b61044660008383611419565b5050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061052257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156104d557600080fd5b505afa1580156104e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050d9190611ea2565b6001600160a01b0316336001600160a01b0316145b61052b57600080fd5b61ffff61054061012083016101008401611f40565b61ffff166105546040840160208501611f40565b61ffff166105656020850185611f40565b61ffff16010111156105895760405162461bcd60e51b815260040161024f906124a1565b61059960a0820160808301611f40565b61ffff16158015906105bd57506105b660c0820160a08301611f40565b61ffff1615155b80156105dc57506105d5610100820160e08301611f40565b61ffff1615155b6105f85760405162461bcd60e51b815260040161024f90612444565b811561061557806202000061060d82826125a2565b905050610627565b806202000161062482826125a2565b50505b7ffde738fae78aad21a8ad5935e1ff28b89cea38834539a91ae210ba7a22c067a582826040516106589291906122bf565b60405180910390a15050565b60008162010000811061067657600080fd5b600290810291909101805460019091015460ff82169350610100820463ffffffff1692600160281b830460060b92600160601b90046001600160a01b0316916001600160581b03811691600160581b8204900b90600160701b90046001600160901b031687565b620200005461ffff8082169162010000810482169163ffffffff600160201b8304811692600160401b8104821692600160601b8204811692600160701b8304821692600160801b810490911691600160a01b8204811691600160b01b90041689565b620200015461ffff8082169162010000810482169163ffffffff600160201b8304811692600160401b8104821692600160601b8204811692600160701b8304821692600160801b810490911691600160a01b8204811691600160b01b90041689565b600080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107ec5760405162461bcd60e51b815260040161024f90612470565b6000806107fc8189898989611478565b915091506108b2600f836001600160581b03168161081657fe5b6040805161012081018252620200005461ffff80821683526201000082048116602084015263ffffffff600160201b8304811694840194909452600160401b820484166060840152600160601b820481166080840152600160701b8204811660a0840152600160801b820490931660c0830152600160a01b8104831660e0830152600160b01b90049091166101008201529190049083906115f7565b935061095f600f6001600160581b0384166040805161012081018252620200015461ffff80821683526201000082048116602084015263ffffffff600160201b8304811694840194909452600160401b820484166060840152600160601b820481166080840152600160701b8204811660a0840152600160801b820490931660c0830152600160a01b8104831660e0830152600160b01b90049091166101008201529190049083906115f7565b9250505094509492505050565b600080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109b75760405162461bcd60e51b815260040161024f90612470565b6109c5600087878787611478565b6001600160581b039091169250905094509492505050565b6060808080336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a2a5760405162461bcd60e51b815260040161024f90612470565b610a3960008a8a8a8a8a611689565b929c919b50995090975095505050505050565b610a54611e22565b85870363ffffffff87161580610a915750610a91898661ffff16620100008110610a7a57fe5b6002020154610100900463ffffffff16828a6118bd565b15610c14576000898661ffff16620100008110610aaa57fe5b6040805160e081018252600292830293909301805460ff811615158552610100810463ffffffff90811660208701819052600160281b8304600690810b810b900b94870194909452600160601b9091046001600160a01b031660608601526001909101546001600160581b0381166080860152600160581b8104840b840b90930b60a0850152600160701b9092046001600160901b031660c084015291925083161415610b5a5791506110109050565b6000610b738b8b8a8a8a876020015188604001516118e6565b90508761ffff88811690881614610bf957610b8c611e22565b60008d60018b0361ffff16620100008110610ba357fe5b60020201805463ffffffff610100820481166020808701829052600160281b909304600690810b810b810b6040808901829052948b0151948b0151959650919093039091169203900b81610bf357fe5b05925050505b610c0983858b848a876000611a50565b945050505050611010565b610c29898561ffff16620100008110610a7a57fe5b610c60576040805162461bcd60e51b815260206004820152600360248201526213d31160ea1b604482015290519081900360640190fd5b600080610c708b8b858a8a611b54565b6040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900460060b60060b60060b815260200160008201600c9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160581b03166001600160581b03166001600160581b0316815260200160018201600b9054906101000a900460020b60020b60020b815260200160018201600e9054906101000a90046001600160901b03166001600160901b03166001600160901b03168152505091506040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900460060b60060b60060b815260200160008201600c9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160581b03166001600160581b03166001600160581b0316815260200160018201600b9054906101000a900460020b60020b60020b815260200160018201600e9054906101000a90046001600160901b03166001600160901b03166001600160901b0316815250509150806020015163ffffffff168363ffffffff161415610ebc579250611010915050565b816020015163ffffffff168363ffffffff161461100b5760008260200151826020015103905060008360200151850390508063ffffffff168263ffffffff16856040015185604001510360060b81610f1057fe5b0502846040018181510191509060060b908160060b815250508163ffffffff168163ffffffff1685606001518560600151036001600160a01b03160281610f5357fe5b0484606001818151019150906001600160a01b031690816001600160a01b0316815250508063ffffffff168263ffffffff1685608001518560800151036001600160581b031681610fa057fe5b040284608001818151019150906001600160581b031690816001600160581b0316815250508063ffffffff168263ffffffff168560c001518560c00151036001600160901b031681610fee57fe5b60c0870180516001600160901b0393909204939093020116905250505b509150505b979650505050505050565b600080878761ffff1662010000811061103057fe5b60020201805490915063ffffffff8781166101009092041614156110575786915050610329565b6040805160e081018252825460ff811615158252610100810463ffffffff166020830152600160281b8104600690810b810b900b92820192909252600160601b9091046001600160a01b031660608201526001808301546001600160581b0381166080840152600160581b8104600290810b810b900b60a0840152600160701b90046001600160901b031660c08301528801925060008961ffff85166201000081106110ff57fe5b600202015460ff161561110f5750825b60006111288b8a8a8d86886020015189604001516118e6565b90508761ffff8b8116908416146111995760008c60018d0361ffff1662010000811061115057fe5b6002020180546020870151604088015192935063ffffffff6101008304811693600160281b909304600690810b939285900390911691839003900b8161119257fe5b0593505050505b6111a8848b8b848c878d611a50565b8c8761ffff166201000081106111ba57fe5b825160029182029290920180546020850151604086015160608701516001600160a01b0316600160601b026001600160601b0360069290920b66ffffffffffffff16600160281b02600160281b600160601b031963ffffffff9094166101000264ffffffff001998151560ff1990961695909517979097169390931791909116949094179390931692909217825560808301516001909201805460a085015160c0909501516001600160901b0316600160701b026001600160701b039590930b62ffffff16600160581b0262ffffff60581b196001600160581b039095166001600160581b03199092169190911793909316929092179290921691909117905550505050509695505050505050565b600060ff82901d808318819003806112e45760009250611412565b806001600160801b82106112fd5760809190911c9060401b5b600160401b82106113135760409190911c9060201b5b600160201b82106113295760209190911c9060101b5b62010000821061133e5760109190911c9060081b5b61010082106113525760089190911c9060041b5b601082106113655760049190911c9060021b5b600882106113715760011b5b600181848161137c57fe5b048201901c9050600181848161138e57fe5b048201901c905060018184816113a057fe5b048201901c905060018184816113b257fe5b048201901c905060018184816113c457fe5b048201901c905060018184816113d657fe5b048201901c905060018184816113e857fe5b048201901c905060008184816113fa57fe5b04905080821061140a578061140c565b815b95505050505b5050919050565b825460ff161561142857600080fd5b825463ffffffff9290921661010002600160ff19909316831764ffffffff0019161783559101805462ffffff60581b1916600160581b62ffffff60029490940b9390931692909202919091179055565b6000808087600186018161ffff821662010000811061149357fe5b600202015460ff16156114bc57898161ffff166201000081106114b257fe5b6002020191508092505b60006114ce8b8b60008c8c898d610a4c565b8354909150610100900463ffffffff166114ef816201517f198d018d6118bd565b156115575760006115088d8d620151808e8e8b8f610a4c565b90506201518063ffffffff1681608001518460800151036001600160581b03168161152f57fe5b0460398260c001518560c00151036001600160901b0316901c975097505050505050506115ed565b8063ffffffff168b63ffffffff16146115e75760008460010160009054906101000a90046001600160581b03169050600085600101600e9054906101000a90046001600160901b03169050828d0363ffffffff16828560800151036001600160581b0316816115c257fe5b046039828660c00151036001600160901b0316901c98509850505050505050506115ed565b50505050505b9550959350505050565b600080611621856001600160581b03168460a001518560200151866060015163ffffffff16611c5b565b611648866001600160581b031685608001518660000151876040015163ffffffff16611c5b565b01905061ffff81111561165a575061ffff5b611674848460e00151838660c0015163ffffffff16611c5b565b83610100015161ffff16019150509392505050565b60608060608087516001600160401b03811180156116a657600080fd5b506040519080825280602002602001820160405280156116d0578160200160208202803683370190505b50935087516001600160401b03811180156116ea57600080fd5b50604051908082528060200260200182016040528015611714578160200160208202803683370190505b50925087516001600160401b038111801561172e57600080fd5b50604051908082528060200260200182016040528015611758578160200160208202803683370190505b50915087516001600160401b038111801561177257600080fd5b5060405190808252806020026020018201604052801561179c578160200160208202803683370190505b5090506000600187018b61ffff82166201000081106117b757fe5b600202015460ff16156117c8578091505b6117d0611e22565b60005b8b518110156118ac576117fe8e8e8e84815181106117ed57fe5b60200260200101518e8e898f610a4c565b91508160400151826060015183608001518460c00151816001600160581b03169150806001600160901b031690508b858151811061183857fe5b602002602001018b868151811061184b57fe5b602002602001018b878151811061185e57fe5b602002602001018b888151811061187157fe5b60209081029190910101939093526001600160701b039093169091526001600160a01b039092169052600691820b90910b90526001016117d3565b505050509650965096509692505050565b63ffffffff8082168482168110918416118114156103e457505063ffffffff9081169116111590565b600080888561ffff166201000081106118fb57fe5b6002020154610100900463ffffffff16905060008961ffff871662010000811061192157fe5b6002020154600160281b900460060b9050611943826201517f198b018b6118bd565b15611a095761195885620151808b038b6118bd565b156119c65760018703965060008a8861ffff1662010000811061197757fe5b60020201805490915060ff16611990578860020b6119bb565b805463ffffffff6101008204811688031690600160281b9004600690810b8703900b816119b957fe5b055b60060b935050611a04565b60006119db8b8b620151808c8c8c6000610a4c565b9050620151808a87030163ffffffff168160400151860360060b816119fc57fe5b0560060b9350505b611a43565b8163ffffffff168563ffffffff1614611a385781850363ffffffff1681850360060b81611a3257fe5b05611a3d565b8760020b5b60060b92505b5050979650505050505050565b611a58611e22565b60208801805160018a5263ffffffff89811690925260408a018051918a0392831660028a900b02909101600690810b900b90526001600160801b038516611aa0576001611aa2565b845b6001600160801b031663ffffffff60801b608083901b1681611ac057fe5b0489606001818151019150906001600160a01b031690816001600160a01b031681525050611b078163ffffffff168760020b8960020b8c60a0015160020b8860020b611d05565b60808a018051919091016001600160581b031690525050600291820b90910b60a087015260c0860180516001600160801b03929092169091016001600160901b0316905250929392505050565b60008061ffff8084169082908616821115611b7857620100008661ffff1601611b7e565b8561ffff165b905081810160011c5b898161ffff16620100008110611b9957fe5b60020201805490955060ff811690610100900463ffffffff168115611c4657611bc3818b8d6118bd565b15611c3a578b8360010161ffff16620100008110611bdd57fe5b60020201805490965060ff811690610100900463ffffffff168115611c2357611c078c828f6118bd565b15611c1857505050505050506115ed565b846001019650611c33565b508796506115ed95505050505050565b5050611c41565b6001830393505b611c4d565b8260010194505b50505081810160011c611b87565b600081851115611cb55781850394508361ffff166006028510611c83575061ffff8216611cfd565b600861ffff85160a6000611c98878784611d5a565b9050808201818661ffff160281611cab57fe5b0492505050611cfd565b93810393600661ffff8516028510611ccf57506000611cfd565b600861ffff85160a6000611ce4878784611d5a565b8201905080828661ffff160281611cf757fe5b04925050505b949350505050565b6000828203858503038386038702600180890189026002808b02929092018102916006818c0a81029180870a8502868802850283020190860a8d029091020181611d4b57fe5b059a9950505050505050505050565b808361ffff84168281611d6957fe5b049250828102820191508361ffff168381611d8057fe5b0492508402600281840204820191508361ffff168381611d9c57fe5b0492508402600681840204820191508361ffff168381611db857fe5b0492508402601881840204820191508361ffff168381611dd457fe5b0492508402607881840204820191508361ffff168381611df057fe5b04925084026102d08184020491909101908402619d80818602046113b061ffff86168302040182019150509392505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b8035600281900b8114611e7057600080fd5b919050565b80356001600160801b0381168114611e7057600080fd5b8035611e708161275d565b8035611e7081612770565b600060208284031215611eb3578081fd5b81516001600160a01b03811681146103e4578182fd5b600080828403610140811215611edd578182fd5b83358015158114611eec578283fd5b9250610120601f1982011215611f00578182fd5b506020830190509250929050565b600080600060608486031215611f22578081fd5b611f2b84611e75565b95602085013595506040909401359392505050565b600060208284031215611f51578081fd5b81356103e48161275d565b600080600080600060a08688031215611f73578081fd5b8535611f7e8161275d565b94506020860135611f8e81612770565b9350611f9c60408701611e5e565b9250611faa60608701611e75565b9150611fb860808701611e75565b90509295509295909350565b600060208284031215611fd5578081fd5b5035919050565b600080600080600060a08688031215611ff3578081fd5b8535611ffe81612770565b94506020868101356001600160401b038082111561201a578384fd5b818901915089601f83011261202d578384fd5b81358181111561203957fe5b8381026040518582820101818110858211171561205257fe5b604052828152858101935084860182860187018e1015612070578788fd5b8795505b838610156120995761208581611e97565b855260019590950194938601938601612074565b508099505050505050506120af60408701611e5e565b9250611faa60608701611e8c565b600080604083850312156120cf578182fd5b82356120da81612770565b91506120e860208401611e5e565b90509250929050565b60008060008060808587031215612106578384fd5b843561211181612770565b935061211f60208601611e5e565b9250604085013561212f8161275d565b915061213d60608601611e75565b905092959194509250565b600080600080600060a0868803121561215f578081fd5b853561216a81612770565b9450602086013561217a81612770565b935061218860408701611e5e565b92506060860135611faa8161275d565b6000815180845260208085019450808401835b838110156121d05781516001600160701b0316875295820195908201906001016121ab565b509495945050505050565b6000815180845260208085019450808401835b838110156121d0578151875295820195908201906001016121ee565b61ffff169052565b63ffffffff169052565b6080808252855190820181905260009060209060a0840190828901845b8281101561225857815160060b84529284019290840190600101612239565b50505083810382850152865180825287830191830190845b818110156122955783516001600160a01b031683529284019291840191600101612270565b505084810360408601526122a98188612198565b92505050828103606084015261101081856121db565b821515815261014081016122de602083016122d985611e8c565b61220a565b6122ea60208401611e8c565b6122f7604084018261220a565b5061230460408401611e97565b6123116060840182612212565b5061231e60608401611e97565b61232b6080840182612212565b5061233860808401611e8c565b61234560a084018261220a565b5061235260a08401611e8c565b61235f60c084018261220a565b5061236c60c08401611e97565b61237960e0840182612212565b5061238660e08401611e8c565b6101006123958185018361220a565b6123a0818601611e8c565b9150506123b161012084018261220a565b509392505050565b961515875263ffffffff95909516602087015260069390930b60408601526001600160a01b039190911660608501526001600160581b0316608084015260020b60a08301526001600160901b031660c082015260e00190565b60069490940b84526001600160a01b039290921660208401526001600160701b03166040830152606082015260800190565b602080825260129082015271047616d6d6173206d757374206265203e20360741b604082015260600190565b6020808252601790820152766f6e6c7920706f6f6c2063616e2063616c6c207468697360481b604082015260600190565b60208082526010908201526f13585e0819995948195e18d95959195960821b604082015260600190565b6001600160701b03929092168252602082015260400190565b6001600160801b0391909116815260200190565b61ffff91909116815260200190565b61ffff92831681529116602082015260400190565b61ffff998a168152978916602089015263ffffffff96871660408901529486166060880152928716608087015290861660a086015290921660c084015290831660e08301529091166101008201526101200190565b63ffffffff91909116815260200190565b6000813561258f8161275d565b92915050565b6000813561258f81612770565b81356125ad8161275d565b815461ffff191661ffff919091161780825560208301356125cd8161275d565b63ffff00008160101b1663ffff000019831617835550506125f96125f360408401612595565b82612717565b61260e61260860608401612595565b8261273a565b61262361261d60808401612582565b82612678565b61263861263260a08401612582565b82612697565b61264d61264760c08401612595565b826126b6565b61266261265c60e08401612582565b826126d9565b6104466126726101008401612582565b826126f8565b805461ffff60601b191660609290921b61ffff60601b16919091179055565b805461ffff60701b191660709290921b61ffff60701b16919091179055565b805463ffffffff60801b191660809290921b63ffffffff60801b16919091179055565b805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b805461ffff60b01b191660b09290921b61ffff60b01b16919091179055565b805463ffffffff60201b191660209290921b63ffffffff60201b16919091179055565b805463ffffffff60401b191660409290921b63ffffffff60401b16919091179055565b61ffff8116811461276d57600080fd5b50565b63ffffffff8116811461276d57600080fdfea164736f6c6343000706000aa164736f6c6343000706000a