APE Price: $1.31 (+0.60%)

Contract

0x368059c1B64090d6e78d51963B8F768dA690FCD7

Overview

APE Balance

Apechain LogoApechain LogoApechain Logo0 APE

APE Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Latest 1 internal transaction

Parent Transaction Hash Block From To
1141862024-10-20 0:59:1838 days ago1729385958  Contract Creation0 APE

Loading...
Loading

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

Contract Name:
DataStorageOperator

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 0 runs

Other Settings:
default evmVersion
File 1 of 8 : 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);
  }
}

File 2 of 8 : 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;
}

File 3 of 8 : 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);
}

File 4 of 8 : 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);
  }
}

File 5 of 8 : 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;
}

File 6 of 8 : 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);
  }
}

File 7 of 8 : 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))
    }
  }
}

File 8 of 8 : 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;
    }
  }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_pool","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"zto","type":"bool"},{"components":[{"internalType":"uint16","name":"alpha1","type":"uint16"},{"internalType":"uint16","name":"alpha2","type":"uint16"},{"internalType":"uint32","name":"beta1","type":"uint32"},{"internalType":"uint32","name":"beta2","type":"uint32"},{"internalType":"uint16","name":"gamma1","type":"uint16"},{"internalType":"uint16","name":"gamma2","type":"uint16"},{"internalType":"uint32","name":"volumeBeta","type":"uint32"},{"internalType":"uint16","name":"volumeGamma","type":"uint16"},{"internalType":"uint16","name":"baseFee","type":"uint16"}],"indexed":false,"internalType":"struct AdaptiveFee.Configuration","name":"feeConfig","type":"tuple"}],"name":"FeeConfiguration","type":"event"},{"inputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"int256","name":"amount0","type":"int256"},{"internalType":"int256","name":"amount1","type":"int256"}],"name":"calculateVolumePerLiquidity","outputs":[{"internalType":"uint128","name":"volumePerLiquidity","type":"uint128"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bool","name":"zto","type":"bool"},{"components":[{"internalType":"uint16","name":"alpha1","type":"uint16"},{"internalType":"uint16","name":"alpha2","type":"uint16"},{"internalType":"uint32","name":"beta1","type":"uint32"},{"internalType":"uint32","name":"beta2","type":"uint32"},{"internalType":"uint16","name":"gamma1","type":"uint16"},{"internalType":"uint16","name":"gamma2","type":"uint16"},{"internalType":"uint32","name":"volumeBeta","type":"uint32"},{"internalType":"uint16","name":"volumeGamma","type":"uint16"},{"internalType":"uint16","name":"baseFee","type":"uint16"}],"internalType":"struct AdaptiveFee.Configuration","name":"_feeConfig","type":"tuple"}],"name":"changeFeeConfiguration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeConfigOtz","outputs":[{"internalType":"uint16","name":"alpha1","type":"uint16"},{"internalType":"uint16","name":"alpha2","type":"uint16"},{"internalType":"uint32","name":"beta1","type":"uint32"},{"internalType":"uint32","name":"beta2","type":"uint32"},{"internalType":"uint16","name":"gamma1","type":"uint16"},{"internalType":"uint16","name":"gamma2","type":"uint16"},{"internalType":"uint32","name":"volumeBeta","type":"uint32"},{"internalType":"uint16","name":"volumeGamma","type":"uint16"},{"internalType":"uint16","name":"baseFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeConfigZto","outputs":[{"internalType":"uint16","name":"alpha1","type":"uint16"},{"internalType":"uint16","name":"alpha2","type":"uint16"},{"internalType":"uint32","name":"beta1","type":"uint32"},{"internalType":"uint32","name":"beta2","type":"uint32"},{"internalType":"uint16","name":"gamma1","type":"uint16"},{"internalType":"uint16","name":"gamma2","type":"uint16"},{"internalType":"uint32","name":"volumeBeta","type":"uint32"},{"internalType":"uint16","name":"volumeGamma","type":"uint16"},{"internalType":"uint16","name":"baseFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"time","type":"uint32"},{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint16","name":"index","type":"uint16"},{"internalType":"uint128","name":"liquidity","type":"uint128"}],"name":"getAverages","outputs":[{"internalType":"uint112","name":"TWVolatilityAverage","type":"uint112"},{"internalType":"uint256","name":"TWVolumePerLiqAverage","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_time","type":"uint32"},{"internalType":"int24","name":"_tick","type":"int24"},{"internalType":"uint16","name":"_index","type":"uint16"},{"internalType":"uint128","name":"_liquidity","type":"uint128"}],"name":"getFees","outputs":[{"internalType":"uint16","name":"feeZto","type":"uint16"},{"internalType":"uint16","name":"feeOtz","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"time","type":"uint32"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"},{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint16","name":"index","type":"uint16"},{"internalType":"uint128","name":"liquidity","type":"uint128"}],"name":"getSingleTimepoint","outputs":[{"internalType":"int56","name":"tickCumulative","type":"int56"},{"internalType":"uint160","name":"secondsPerLiquidityCumulative","type":"uint160"},{"internalType":"uint112","name":"volatilityCumulative","type":"uint112"},{"internalType":"uint256","name":"volumePerAvgLiquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"time","type":"uint32"},{"internalType":"uint32[]","name":"secondsAgos","type":"uint32[]"},{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint16","name":"index","type":"uint16"},{"internalType":"uint128","name":"liquidity","type":"uint128"}],"name":"getTimepoints","outputs":[{"internalType":"int56[]","name":"tickCumulatives","type":"int56[]"},{"internalType":"uint160[]","name":"secondsPerLiquidityCumulatives","type":"uint160[]"},{"internalType":"uint112[]","name":"volatilityCumulatives","type":"uint112[]"},{"internalType":"uint256[]","name":"volumePerAvgLiquiditys","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"time","type":"uint32"},{"internalType":"int24","name":"tick","type":"int24"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"timepoints","outputs":[{"internalType":"bool","name":"initialized","type":"bool"},{"internalType":"uint32","name":"blockTimestamp","type":"uint32"},{"internalType":"int56","name":"tickCumulative","type":"int56"},{"internalType":"uint160","name":"secondsPerLiquidityCumulative","type":"uint160"},{"internalType":"uint88","name":"volatilityCumulative","type":"uint88"},{"internalType":"int24","name":"averageTick","type":"int24"},{"internalType":"uint144","name":"volumePerLiquidityCumulative","type":"uint144"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"window","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint16","name":"index","type":"uint16"},{"internalType":"uint32","name":"blockTimestamp","type":"uint32"},{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint128","name":"volumePerLiquidity","type":"uint128"}],"name":"write","outputs":[{"internalType":"uint16","name":"indexUpdated","type":"uint16"}],"stateMutability":"nonpayable","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100a45760003560e01c806314c54079146100a95780631dd486f2146100d557806336e52fee146100f5578063461645bf14610115578063475fb80c1461012a578063525331111461013f57806374eceae614610152578063824e8e871461017857806390577ef614610195578063a80b96a11461019d578063bc2e0181146101be578063fd31e988146101df575b600080fd5b6100bc6100b7366004612148565b610202565b6040516100cc9493929190612412565b60405180910390f35b6100e86100e3366004611f5c565b6102d0565b6040516100cc91906124f8565b610108610103366004611f0e565b610333565b6040516100cc91906124e4565b61011d6103eb565b6040516100cc9190612571565b61013d6101383660046120bd565b6103f2565b005b61013d61014d366004611ec9565b61044a565b610165610160366004611fc4565b610664565b6040516100cc97969594939291906123b9565b6101806106dd565b6040516100cc9998979695949392919061251c565b61018061073f565b6101b06101ab3660046120f1565b6107a1565b6040516100cc929190612507565b6101d16101cc3660046120f1565b61096c565b6040516100cc9291906124cb565b6101f26101ed366004611fdc565b6109dd565b6040516100cc949392919061221c565b6000808080336001600160a01b037f0000000000000000000000006e904258feda98186ca29c7e05076f3d299afbc316146102585760405162461bcd60e51b815260040161024f90612470565b60405180910390fd5b6000600187018161ffff821662010000811061027057fe5b600202015460ff1615610281578091505b6000610292818d8d8d8d888e610a4c565b60408101516060820151608083015160c090930151919f909e506001600160581b039092169c506001600160901b03169a5098505050505050505050565b6000336001600160a01b037f0000000000000000000000006e904258feda98186ca29c7e05076f3d299afbc3161461031a5760405162461bcd60e51b815260040161024f90612470565b6103296000878787878761101b565b9695505050505050565b60008061033f836112c9565b610348856112c9565b0290506000600160c01b821061038d576000866001600160801b031611610370576001610372565b855b6001600160801b03166000198161038557fe5b0490506103c0565b6000866001600160801b0316116103a55760016103a7565b855b6001600160801b0316604083901b816103bc57fe5b0490505b610c3560451b81106103db57610c3560451b925050506103e4565b91506103e49050565b9392505050565b6201518090565b336001600160a01b037f0000000000000000000000006e904258feda98186ca29c7e05076f3d299afbc3161461043a5760405162461bcd60e51b815260040161024f90612470565b61044660008383611419565b5050565b336001600160a01b037f00000000000000000000000010aa510d94e094bd643677bd2964c3ee085daffc16148061052257507f00000000000000000000000010aa510d94e094bd643677bd2964c3ee085daffc6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156104d557600080fd5b505afa1580156104e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050d9190611ea2565b6001600160a01b0316336001600160a01b0316145b61052b57600080fd5b61ffff61054061012083016101008401611f40565b61ffff166105546040840160208501611f40565b61ffff166105656020850185611f40565b61ffff16010111156105895760405162461bcd60e51b815260040161024f906124a1565b61059960a0820160808301611f40565b61ffff16158015906105bd57506105b660c0820160a08301611f40565b61ffff1615155b80156105dc57506105d5610100820160e08301611f40565b61ffff1615155b6105f85760405162461bcd60e51b815260040161024f90612444565b811561061557806202000061060d82826125a2565b905050610627565b806202000161062482826125a2565b50505b7ffde738fae78aad21a8ad5935e1ff28b89cea38834539a91ae210ba7a22c067a582826040516106589291906122bf565b60405180910390a15050565b60008162010000811061067657600080fd5b600290810291909101805460019091015460ff82169350610100820463ffffffff1692600160281b830460060b92600160601b90046001600160a01b0316916001600160581b03811691600160581b8204900b90600160701b90046001600160901b031687565b620200005461ffff8082169162010000810482169163ffffffff600160201b8304811692600160401b8104821692600160601b8204811692600160701b8304821692600160801b810490911691600160a01b8204811691600160b01b90041689565b620200015461ffff8082169162010000810482169163ffffffff600160201b8304811692600160401b8104821692600160601b8204811692600160701b8304821692600160801b810490911691600160a01b8204811691600160b01b90041689565b600080336001600160a01b037f0000000000000000000000006e904258feda98186ca29c7e05076f3d299afbc316146107ec5760405162461bcd60e51b815260040161024f90612470565b6000806107fc8189898989611478565b915091506108b2600f836001600160581b03168161081657fe5b6040805161012081018252620200005461ffff80821683526201000082048116602084015263ffffffff600160201b8304811694840194909452600160401b820484166060840152600160601b820481166080840152600160701b8204811660a0840152600160801b820490931660c0830152600160a01b8104831660e0830152600160b01b90049091166101008201529190049083906115f7565b935061095f600f6001600160581b0384166040805161012081018252620200015461ffff80821683526201000082048116602084015263ffffffff600160201b8304811694840194909452600160401b820484166060840152600160601b820481166080840152600160701b8204811660a0840152600160801b820490931660c0830152600160a01b8104831660e0830152600160b01b90049091166101008201529190049083906115f7565b9250505094509492505050565b600080336001600160a01b037f0000000000000000000000006e904258feda98186ca29c7e05076f3d299afbc316146109b75760405162461bcd60e51b815260040161024f90612470565b6109c5600087878787611478565b6001600160581b039091169250905094509492505050565b6060808080336001600160a01b037f0000000000000000000000006e904258feda98186ca29c7e05076f3d299afbc31614610a2a5760405162461bcd60e51b815260040161024f90612470565b610a3960008a8a8a8a8a611689565b929c919b50995090975095505050505050565b610a54611e22565b85870363ffffffff87161580610a915750610a91898661ffff16620100008110610a7a57fe5b6002020154610100900463ffffffff16828a6118bd565b15610c14576000898661ffff16620100008110610aaa57fe5b6040805160e081018252600292830293909301805460ff811615158552610100810463ffffffff90811660208701819052600160281b8304600690810b810b900b94870194909452600160601b9091046001600160a01b031660608601526001909101546001600160581b0381166080860152600160581b8104840b840b90930b60a0850152600160701b9092046001600160901b031660c084015291925083161415610b5a5791506110109050565b6000610b738b8b8a8a8a876020015188604001516118e6565b90508761ffff88811690881614610bf957610b8c611e22565b60008d60018b0361ffff16620100008110610ba357fe5b60020201805463ffffffff610100820481166020808701829052600160281b909304600690810b810b810b6040808901829052948b0151948b0151959650919093039091169203900b81610bf357fe5b05925050505b610c0983858b848a876000611a50565b945050505050611010565b610c29898561ffff16620100008110610a7a57fe5b610c60576040805162461bcd60e51b815260206004820152600360248201526213d31160ea1b604482015290519081900360640190fd5b600080610c708b8b858a8a611b54565b6040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900460060b60060b60060b815260200160008201600c9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160581b03166001600160581b03166001600160581b0316815260200160018201600b9054906101000a900460020b60020b60020b815260200160018201600e9054906101000a90046001600160901b03166001600160901b03166001600160901b03168152505091506040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900460060b60060b60060b815260200160008201600c9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160581b03166001600160581b03166001600160581b0316815260200160018201600b9054906101000a900460020b60020b60020b815260200160018201600e9054906101000a90046001600160901b03166001600160901b03166001600160901b0316815250509150806020015163ffffffff168363ffffffff161415610ebc579250611010915050565b816020015163ffffffff168363ffffffff161461100b5760008260200151826020015103905060008360200151850390508063ffffffff168263ffffffff16856040015185604001510360060b81610f1057fe5b0502846040018181510191509060060b908160060b815250508163ffffffff168163ffffffff1685606001518560600151036001600160a01b03160281610f5357fe5b0484606001818151019150906001600160a01b031690816001600160a01b0316815250508063ffffffff168263ffffffff1685608001518560800151036001600160581b031681610fa057fe5b040284608001818151019150906001600160581b031690816001600160581b0316815250508063ffffffff168263ffffffff168560c001518560c00151036001600160901b031681610fee57fe5b60c0870180516001600160901b0393909204939093020116905250505b509150505b979650505050505050565b600080878761ffff1662010000811061103057fe5b60020201805490915063ffffffff8781166101009092041614156110575786915050610329565b6040805160e081018252825460ff811615158252610100810463ffffffff166020830152600160281b8104600690810b810b900b92820192909252600160601b9091046001600160a01b031660608201526001808301546001600160581b0381166080840152600160581b8104600290810b810b900b60a0840152600160701b90046001600160901b031660c08301528801925060008961ffff85166201000081106110ff57fe5b600202015460ff161561110f5750825b60006111288b8a8a8d86886020015189604001516118e6565b90508761ffff8b8116908416146111995760008c60018d0361ffff1662010000811061115057fe5b6002020180546020870151604088015192935063ffffffff6101008304811693600160281b909304600690810b939285900390911691839003900b8161119257fe5b0593505050505b6111a8848b8b848c878d611a50565b8c8761ffff166201000081106111ba57fe5b825160029182029290920180546020850151604086015160608701516001600160a01b0316600160601b026001600160601b0360069290920b66ffffffffffffff16600160281b02600160281b600160601b031963ffffffff9094166101000264ffffffff001998151560ff1990961695909517979097169390931791909116949094179390931692909217825560808301516001909201805460a085015160c0909501516001600160901b0316600160701b026001600160701b039590930b62ffffff16600160581b0262ffffff60581b196001600160581b039095166001600160581b03199092169190911793909316929092179290921691909117905550505050509695505050505050565b600060ff82901d808318819003806112e45760009250611412565b806001600160801b82106112fd5760809190911c9060401b5b600160401b82106113135760409190911c9060201b5b600160201b82106113295760209190911c9060101b5b62010000821061133e5760109190911c9060081b5b61010082106113525760089190911c9060041b5b601082106113655760049190911c9060021b5b600882106113715760011b5b600181848161137c57fe5b048201901c9050600181848161138e57fe5b048201901c905060018184816113a057fe5b048201901c905060018184816113b257fe5b048201901c905060018184816113c457fe5b048201901c905060018184816113d657fe5b048201901c905060018184816113e857fe5b048201901c905060008184816113fa57fe5b04905080821061140a578061140c565b815b95505050505b5050919050565b825460ff161561142857600080fd5b825463ffffffff9290921661010002600160ff19909316831764ffffffff0019161783559101805462ffffff60581b1916600160581b62ffffff60029490940b9390931692909202919091179055565b6000808087600186018161ffff821662010000811061149357fe5b600202015460ff16156114bc57898161ffff166201000081106114b257fe5b6002020191508092505b60006114ce8b8b60008c8c898d610a4c565b8354909150610100900463ffffffff166114ef816201517f198d018d6118bd565b156115575760006115088d8d620151808e8e8b8f610a4c565b90506201518063ffffffff1681608001518460800151036001600160581b03168161152f57fe5b0460398260c001518560c00151036001600160901b0316901c975097505050505050506115ed565b8063ffffffff168b63ffffffff16146115e75760008460010160009054906101000a90046001600160581b03169050600085600101600e9054906101000a90046001600160901b03169050828d0363ffffffff16828560800151036001600160581b0316816115c257fe5b046039828660c00151036001600160901b0316901c98509850505050505050506115ed565b50505050505b9550959350505050565b600080611621856001600160581b03168460a001518560200151866060015163ffffffff16611c5b565b611648866001600160581b031685608001518660000151876040015163ffffffff16611c5b565b01905061ffff81111561165a575061ffff5b611674848460e00151838660c0015163ffffffff16611c5b565b83610100015161ffff16019150509392505050565b60608060608087516001600160401b03811180156116a657600080fd5b506040519080825280602002602001820160405280156116d0578160200160208202803683370190505b50935087516001600160401b03811180156116ea57600080fd5b50604051908082528060200260200182016040528015611714578160200160208202803683370190505b50925087516001600160401b038111801561172e57600080fd5b50604051908082528060200260200182016040528015611758578160200160208202803683370190505b50915087516001600160401b038111801561177257600080fd5b5060405190808252806020026020018201604052801561179c578160200160208202803683370190505b5090506000600187018b61ffff82166201000081106117b757fe5b600202015460ff16156117c8578091505b6117d0611e22565b60005b8b518110156118ac576117fe8e8e8e84815181106117ed57fe5b60200260200101518e8e898f610a4c565b91508160400151826060015183608001518460c00151816001600160581b03169150806001600160901b031690508b858151811061183857fe5b602002602001018b868151811061184b57fe5b602002602001018b878151811061185e57fe5b602002602001018b888151811061187157fe5b60209081029190910101939093526001600160701b039093169091526001600160a01b039092169052600691820b90910b90526001016117d3565b505050509650965096509692505050565b63ffffffff8082168482168110918416118114156103e457505063ffffffff9081169116111590565b600080888561ffff166201000081106118fb57fe5b6002020154610100900463ffffffff16905060008961ffff871662010000811061192157fe5b6002020154600160281b900460060b9050611943826201517f198b018b6118bd565b15611a095761195885620151808b038b6118bd565b156119c65760018703965060008a8861ffff1662010000811061197757fe5b60020201805490915060ff16611990578860020b6119bb565b805463ffffffff6101008204811688031690600160281b9004600690810b8703900b816119b957fe5b055b60060b935050611a04565b60006119db8b8b620151808c8c8c6000610a4c565b9050620151808a87030163ffffffff168160400151860360060b816119fc57fe5b0560060b9350505b611a43565b8163ffffffff168563ffffffff1614611a385781850363ffffffff1681850360060b81611a3257fe5b05611a3d565b8760020b5b60060b92505b5050979650505050505050565b611a58611e22565b60208801805160018a5263ffffffff89811690925260408a018051918a0392831660028a900b02909101600690810b900b90526001600160801b038516611aa0576001611aa2565b845b6001600160801b031663ffffffff60801b608083901b1681611ac057fe5b0489606001818151019150906001600160a01b031690816001600160a01b031681525050611b078163ffffffff168760020b8960020b8c60a0015160020b8860020b611d05565b60808a018051919091016001600160581b031690525050600291820b90910b60a087015260c0860180516001600160801b03929092169091016001600160901b0316905250929392505050565b60008061ffff8084169082908616821115611b7857620100008661ffff1601611b7e565b8561ffff165b905081810160011c5b898161ffff16620100008110611b9957fe5b60020201805490955060ff811690610100900463ffffffff168115611c4657611bc3818b8d6118bd565b15611c3a578b8360010161ffff16620100008110611bdd57fe5b60020201805490965060ff811690610100900463ffffffff168115611c2357611c078c828f6118bd565b15611c1857505050505050506115ed565b846001019650611c33565b508796506115ed95505050505050565b5050611c41565b6001830393505b611c4d565b8260010194505b50505081810160011c611b87565b600081851115611cb55781850394508361ffff166006028510611c83575061ffff8216611cfd565b600861ffff85160a6000611c98878784611d5a565b9050808201818661ffff160281611cab57fe5b0492505050611cfd565b93810393600661ffff8516028510611ccf57506000611cfd565b600861ffff85160a6000611ce4878784611d5a565b8201905080828661ffff160281611cf757fe5b04925050505b949350505050565b6000828203858503038386038702600180890189026002808b02929092018102916006818c0a81029180870a8502868802850283020190860a8d029091020181611d4b57fe5b059a9950505050505050505050565b808361ffff84168281611d6957fe5b049250828102820191508361ffff168381611d8057fe5b0492508402600281840204820191508361ffff168381611d9c57fe5b0492508402600681840204820191508361ffff168381611db857fe5b0492508402601881840204820191508361ffff168381611dd457fe5b0492508402607881840204820191508361ffff168381611df057fe5b04925084026102d08184020491909101908402619d80818602046113b061ffff86168302040182019150509392505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b8035600281900b8114611e7057600080fd5b919050565b80356001600160801b0381168114611e7057600080fd5b8035611e708161275d565b8035611e7081612770565b600060208284031215611eb3578081fd5b81516001600160a01b03811681146103e4578182fd5b600080828403610140811215611edd578182fd5b83358015158114611eec578283fd5b9250610120601f1982011215611f00578182fd5b506020830190509250929050565b600080600060608486031215611f22578081fd5b611f2b84611e75565b95602085013595506040909401359392505050565b600060208284031215611f51578081fd5b81356103e48161275d565b600080600080600060a08688031215611f73578081fd5b8535611f7e8161275d565b94506020860135611f8e81612770565b9350611f9c60408701611e5e565b9250611faa60608701611e75565b9150611fb860808701611e75565b90509295509295909350565b600060208284031215611fd5578081fd5b5035919050565b600080600080600060a08688031215611ff3578081fd5b8535611ffe81612770565b94506020868101356001600160401b038082111561201a578384fd5b818901915089601f83011261202d578384fd5b81358181111561203957fe5b8381026040518582820101818110858211171561205257fe5b604052828152858101935084860182860187018e1015612070578788fd5b8795505b838610156120995761208581611e97565b855260019590950194938601938601612074565b508099505050505050506120af60408701611e5e565b9250611faa60608701611e8c565b600080604083850312156120cf578182fd5b82356120da81612770565b91506120e860208401611e5e565b90509250929050565b60008060008060808587031215612106578384fd5b843561211181612770565b935061211f60208601611e5e565b9250604085013561212f8161275d565b915061213d60608601611e75565b905092959194509250565b600080600080600060a0868803121561215f578081fd5b853561216a81612770565b9450602086013561217a81612770565b935061218860408701611e5e565b92506060860135611faa8161275d565b6000815180845260208085019450808401835b838110156121d05781516001600160701b0316875295820195908201906001016121ab565b509495945050505050565b6000815180845260208085019450808401835b838110156121d0578151875295820195908201906001016121ee565b61ffff169052565b63ffffffff169052565b6080808252855190820181905260009060209060a0840190828901845b8281101561225857815160060b84529284019290840190600101612239565b50505083810382850152865180825287830191830190845b818110156122955783516001600160a01b031683529284019291840191600101612270565b505084810360408601526122a98188612198565b92505050828103606084015261101081856121db565b821515815261014081016122de602083016122d985611e8c565b61220a565b6122ea60208401611e8c565b6122f7604084018261220a565b5061230460408401611e97565b6123116060840182612212565b5061231e60608401611e97565b61232b6080840182612212565b5061233860808401611e8c565b61234560a084018261220a565b5061235260a08401611e8c565b61235f60c084018261220a565b5061236c60c08401611e97565b61237960e0840182612212565b5061238660e08401611e8c565b6101006123958185018361220a565b6123a0818601611e8c565b9150506123b161012084018261220a565b509392505050565b961515875263ffffffff95909516602087015260069390930b60408601526001600160a01b039190911660608501526001600160581b0316608084015260020b60a08301526001600160901b031660c082015260e00190565b60069490940b84526001600160a01b039290921660208401526001600160701b03166040830152606082015260800190565b602080825260129082015271047616d6d6173206d757374206265203e20360741b604082015260600190565b6020808252601790820152766f6e6c7920706f6f6c2063616e2063616c6c207468697360481b604082015260600190565b60208082526010908201526f13585e0819995948195e18d95959195960821b604082015260600190565b6001600160701b03929092168252602082015260400190565b6001600160801b0391909116815260200190565b61ffff91909116815260200190565b61ffff92831681529116602082015260400190565b61ffff998a168152978916602089015263ffffffff96871660408901529486166060880152928716608087015290861660a086015290921660c084015290831660e08301529091166101008201526101200190565b63ffffffff91909116815260200190565b6000813561258f8161275d565b92915050565b6000813561258f81612770565b81356125ad8161275d565b815461ffff191661ffff919091161780825560208301356125cd8161275d565b63ffff00008160101b1663ffff000019831617835550506125f96125f360408401612595565b82612717565b61260e61260860608401612595565b8261273a565b61262361261d60808401612582565b82612678565b61263861263260a08401612582565b82612697565b61264d61264760c08401612595565b826126b6565b61266261265c60e08401612582565b826126d9565b6104466126726101008401612582565b826126f8565b805461ffff60601b191660609290921b61ffff60601b16919091179055565b805461ffff60701b191660709290921b61ffff60701b16919091179055565b805463ffffffff60801b191660809290921b63ffffffff60801b16919091179055565b805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b805461ffff60b01b191660b09290921b61ffff60b01b16919091179055565b805463ffffffff60201b191660209290921b63ffffffff60201b16919091179055565b805463ffffffff60401b191660409290921b63ffffffff60401b16919091179055565b61ffff8116811461276d57600080fd5b50565b63ffffffff8116811461276d57600080fdfea164736f6c6343000706000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

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