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