false
false
0
The new Blockscout UI is now open source! Learn how to deploy it here

Contract Address Details

0x31e4ee367d4f2685BAfcAb9566e9C87E60D48983

Contract Name
FeeManager
Creator
0x077675–fb67cc at 0xb65e4b–036dba
Balance
0 ETH
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
486343
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
FeeManager




Optimization enabled
true
Compiler version
v0.8.18+commit.87f61d96




Optimization runs
5
EVM Version
paris




Verified at
2024-06-07T13:14:43.766273Z

contracts/FeeManager.sol

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "./interfaces/IMultiPositionManager.sol";
import "./interfaces/IBareVaultRegistry.sol";

contract FeeManager is Initializable, OwnableUpgradeable, UUPSUpgradeable {
    struct Fee {
        string feeIdentifier;
        uint256 feeValue;
    }

    mapping(address => Fee[]) public vaultFees;
    mapping(address => uint256) public vaultTotalFees;
    mapping(address => mapping(string => address))
        public withdrawalPermissions;
    address public vaultRegistry;

    event FeeWithdrawn(
        address indexed caller,
        address indexed vault,
        string feeIdentifier,
        address indexed to,
        uint256 amount0,
        uint256 amount1
    );
    event FeesWithdrawn(
        address indexed caller,
        address vault,
        string[] feeIdentifier,
        address[] to,
        uint256[] amount0,
        uint256[] amount1
    );

    event FeesWithdrawnFromMultipleVaults(
        address indexed caller,
        address[] vaults,
        string[][] feeIdentifiers,
        address[][] to,
        uint256[][] amount0,
        uint256[][] amount1
    );
    event FeeUpdated(
        address indexed vault,
        string[] feeIdentifier,
        uint256[] feeValue,
        address[] withdrawer
    );

    constructor() initializer {}

    // Initializer function (replacing the constructor)
    function initialize(address _vaultRegistry) public initializer {
        __UUPSUpgradeable_init();
        __Ownable_init();
        vaultRegistry = _vaultRegistry;
    }

    function setFeeAndWithdrawalPermission(
        address vault,
        string[] memory feeIdentifier,
        uint256[] memory feeValue,
        address[] memory withdrawer
    ) external onlyOwner {
        require(
            feeIdentifier.length == feeValue.length &&
                feeValue.length == withdrawer.length,
            "Input arrays must have the same length"
        );
        //Tortured logic but identifers shouldnt be generally more than 3-4
        areAllUnique(feeIdentifier);
        uint256 totalFeeValue;
        if (vaultFees[vault].length > 0) delete vaultFees[vault]; //Always make to pass all the tiers again when adding more tiers
        for (uint256 i; i < feeIdentifier.length; ) {
            require(
                withdrawer[i] != address(0),
                "Withdrawer address cannot be zero"
            );
            vaultFees[vault].push(
                Fee({ feeIdentifier: feeIdentifier[i], feeValue: feeValue[i] })
            );
            withdrawalPermissions[vault][feeIdentifier[i]] = withdrawer[i];
            totalFeeValue += feeValue[i];
            unchecked {
                i++;
            }
        }
        require(
            totalFeeValue == 10000,
            "Total fee value must be exactly 10000"
        );
        emit FeeUpdated(vault, feeIdentifier, feeValue, withdrawer);
    }

    function setDefaultFeeAndWithdrawalPermission(
        address vault,
        uint256 totalVaultFees,
        string[] memory feeIdentifier,
        uint256[] memory feeValue,
        address[] memory withdrawer
    ) external {
        require(vaultRegistry == msg.sender, "!VaultRegistry");
        require(
            feeIdentifier.length == feeValue.length &&
                feeValue.length == withdrawer.length,
            "Input arrays must have the same length"
        );
        //Tortured logic but identifers shouldnt be generally more than 3-4
        areAllUnique(feeIdentifier);
        require(totalVaultFees <= 10000, "Total fee <= 10000");
        uint256 totalFeeValue;
        for (uint256 i; i < feeIdentifier.length; ) {
            require(
                withdrawer[i] != address(0),
                "Withdrawer address cannot be zero"
            );
            vaultFees[vault].push(
                Fee({ feeIdentifier: feeIdentifier[i], feeValue: feeValue[i] })
            );
            withdrawalPermissions[vault][feeIdentifier[i]] = withdrawer[i];
            totalFeeValue += feeValue[i];
            unchecked {
                i++;
            }
        }
        require(
            totalFeeValue == 10000,
            "Total fee value must be exactly 10000"
        );
        vaultTotalFees[vault] = totalVaultFees;
        emit FeeUpdated(vault, feeIdentifier, feeValue, withdrawer);
    }

    function setMigratedVaultFeeAndWithdrawalPermission() external {
        require(
            IBareVaultRegistry(vaultRegistry)
                .getVaultDetails(msg.sender)
                .vaultAddress == msg.sender,
            "Not A Steer Vault"
        );
        string[] memory feeIdentifiers = new string[](2); //Fee identifiers for steer and strategist
        feeIdentifiers[0] = "STEER_FEES";
        feeIdentifiers[1] = "STRATEGIST_FEES";

        uint256[] memory feeValues = new uint256[](2); //Fee values for steer and strategist
        feeValues[0] = IMultiPositionManager(msg.sender)
            .STEER_FRACTION_OF_FEE();
        feeValues[1] = 100_00 - feeValues[0];

        address[] memory feeWithdrawerAddresses = new address[](2); //Fee withdrawer addresses for steer and strategist
        feeWithdrawerAddresses[0] = IBareVaultRegistry(vaultRegistry).owner(); //steer withdrawer
        feeWithdrawerAddresses[1] = IBareVaultRegistry(vaultRegistry)
            .getStrategyCreatorForVault(msg.sender); //strategist withdrawer

        uint256 totalFees = IMultiPositionManager(msg.sender).TOTAL_FEE();
        require(totalFees <= 10000, "Total fee <= 10000");

        vaultFees[msg.sender].push(
            Fee({ feeIdentifier: feeIdentifiers[0], feeValue: feeValues[0] })
        );
        vaultFees[msg.sender].push(
            Fee({ feeIdentifier: feeIdentifiers[1], feeValue: feeValues[1] })
        );

        withdrawalPermissions[msg.sender][
            feeIdentifiers[0]
        ] = feeWithdrawerAddresses[0];

        withdrawalPermissions[msg.sender][
            feeIdentifiers[1]
        ] = feeWithdrawerAddresses[1];
        vaultTotalFees[msg.sender] = totalFees;
        emit FeeUpdated(
            msg.sender,
            feeIdentifiers,
            feeValues,
            feeWithdrawerAddresses
        );
    }

    function changeFeeWithdrawer(
        address vault,
        string memory feeIdentifier,
        address newWithdrawer
    ) external onlyOwner {
        require(
            newWithdrawer != address(0),
            "New withdrawer address cannot be zero"
        );
        withdrawalPermissions[vault][feeIdentifier] = newWithdrawer;
    }

    function setTotalFees(
        address vault,
        uint256 newTotalFees
    ) external onlyOwner {
        require(newTotalFees <= 10000, "Total fee <= 10000");
        vaultTotalFees[vault] = newTotalFees;
    }

    function withdrawFee(
        address vault,
        string memory feeIdentifier,
        uint256 amount0,
        uint256 amount1
    ) external {
        if (amount0 == 0 && amount1 == 0) {
            amount0 = IMultiPositionManager(vault).accruedFees0(feeIdentifier);
            amount1 = IMultiPositionManager(vault).accruedFees1(feeIdentifier);
            IMultiPositionManager(vault).collectFees(
                feeIdentifier,
                amount0,
                amount1
            );
        } else {
            IMultiPositionManager(vault).collectFees(
                feeIdentifier,
                amount0,
                amount1
            );
        }
        emit FeeWithdrawn(
            msg.sender,
            vault,
            feeIdentifier,
            withdrawalPermissions[vault][feeIdentifier],
            amount0,
            amount1
        );
    }

    function getFees(address vault) public view returns (Fee[] memory) {
        return vaultFees[vault];
    }

    function withdrawMultipleFees(
        address vault,
        string[] memory feeIdentifiers,
        uint256[] memory amount0,
        uint256[] memory amount1
    ) public {
        uint256 length0 = amount0.length;
        uint256 length1 = amount1.length;
        uint256 feeLength = feeIdentifiers.length;
        address[] memory to = new address[](feeLength);
        //If the both arrays are empty then it should go into else to autofetch the fees
        if (length0 > 0 || length1 > 0) {
            //If custom values needs to be passed for claiming fees both the values for amount0 and amount1 needs to be passed
            //If anyone of the arrays is empty or lengths for amounts array and fee identifiers array are not matching it should revert
            require(length0 == length1, "Amounts length not same");
            require(
                length0 == feeLength,
                "Amounts and Identifers length not same"
            );
            for (uint256 i; i < feeLength; ) {
                to[i] = withdrawalPermissions[vault][feeIdentifiers[i]];
                IMultiPositionManager(vault).collectFees(
                    feeIdentifiers[i],
                    amount0[i],
                    amount1[i]
                );
                unchecked {
                    i++;
                }
            }
            emit FeesWithdrawn(
                msg.sender,
                vault,
                feeIdentifiers,
                to,
                amount0,
                amount1
            );
        } else {
            uint256[] memory amt0 = new uint256[](feeLength);
            uint256[] memory amt1 = new uint256[](feeLength);
            for (uint256 i; i < feeLength; ) {
                to[i] = withdrawalPermissions[vault][feeIdentifiers[i]];
                amt0[i] = IMultiPositionManager(vault).accruedFees0(
                    feeIdentifiers[i]
                );
                amt1[i] = IMultiPositionManager(vault).accruedFees1(
                    feeIdentifiers[i]
                );
                IMultiPositionManager(vault).collectFees(
                    feeIdentifiers[i],
                    amt0[i],
                    amt1[i]
                );
                unchecked {
                    i++;
                }
            }
            emit FeesWithdrawn(
                msg.sender,
                vault,
                feeIdentifiers,
                to,
                amt0,
                amt1
            );
        }
    }

    function withdrawFeesFromMultipleVaults(
        address[] memory vaults,
        string[][] memory feeIdentifiers,
        uint256[][] memory amount0,
        uint256[][] memory amount1
    ) public {
        //make sure to pass the same amount of arrays(even if empty) inside the 2d arrays of amount0,amount1 and feeidentifers arrays so that it passes the below condition
        require(
            vaults.length == feeIdentifiers.length &&
                vaults.length == amount0.length &&
                vaults.length == amount1.length,
            "Array lengths must match"
        );

        address[][] memory to = new address[][](vaults.length);
        uint256[][] memory amt0 = new uint256[][](vaults.length);
        uint256[][] memory amt1 = new uint256[][](vaults.length);

        for (uint256 i; i < vaults.length; ) {
            address vault = vaults[i];
            string[] memory feeIds = feeIdentifiers[i];
            uint256 feeLength = feeIds.length;

            to[i] = new address[](feeLength);
            amt0[i] = new uint256[](feeLength);
            amt1[i] = new uint256[](feeLength);
            //If the both arrays at this index are empty then it should go into else to autofetch the fees
            if (amount0[i].length > 0 || amount1[i].length > 0) {
                //If custom values needs to be passed for claiming fees both the values for amount0 and amount1 needs to be passed
                //If anyone of the arrays for this index is empty or lengths for amounts array and fee identifiers array are not matching for this index then it should revert
                require(
                    amount0[i].length == feeLength &&
                        amount1[i].length == feeLength,
                    "Amounts and Identifiers length mismatch"
                );
                for (uint256 j; j < feeLength; ) {
                    to[i][j] = withdrawalPermissions[vault][feeIds[j]];
                    IMultiPositionManager(vault).collectFees(
                        feeIds[j],
                        amount0[i][j],
                        amount1[i][j]
                    );
                    amt0[i][j] = amount0[i][j];
                    amt1[i][j] = amount1[i][j];
                    unchecked {
                        j++;
                    }
                }
            } else {
                for (uint256 j; j < feeLength; ) {
                    to[i][j] = withdrawalPermissions[vault][feeIds[j]];
                    amt0[i][j] = IMultiPositionManager(vault).accruedFees0(
                        feeIds[j]
                    );
                    amt1[i][j] = IMultiPositionManager(vault).accruedFees1(
                        feeIds[j]
                    );
                    IMultiPositionManager(vault).collectFees(
                        feeIds[j],
                        amt0[i][j],
                        amt1[i][j]
                    );
                    unchecked {
                        j++;
                    }
                }
            }
            unchecked {
                i++;
            }
        }

        emit FeesWithdrawnFromMultipleVaults(
            msg.sender,
            vaults,
            feeIdentifiers,
            to,
            amt0,
            amt1
        );
    }

    function _authorizeUpgrade(
        address newImplementation
    ) internal override onlyOwner {}

    function areAllUnique(string[] memory stringArray) public pure {
        for (uint i; i < stringArray.length; ) {
            for (uint j = i + 1; j < stringArray.length; ) {
                if (
                    keccak256(abi.encodePacked(stringArray[i])) ==
                    keccak256(abi.encodePacked(stringArray[j]))
                ) {
                    // Found two identical strings, the array is not unique
                    revert("Same Identifier");
                }
                unchecked {
                    j++;
                }
            }
            unchecked {
                i++;
            }
        }
        // No duplicates found, the array is unique
        return;
    }
}
        

@cryptoalgebra/core/contracts/interfaces/IAlgebraPool.sol

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

import './pool/IAlgebraPoolImmutables.sol';
import './pool/IAlgebraPoolState.sol';
import './pool/IAlgebraPoolDerivedState.sol';
import './pool/IAlgebraPoolActions.sol';
import './pool/IAlgebraPoolPermissionedActions.sol';
import './pool/IAlgebraPoolEvents.sol';

/**
 * @title The interface for a Algebra Pool
 * @dev The pool interface is broken up into many smaller pieces.
 * Credit to Uniswap Labs under GPL-2.0-or-later license:
 * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
 */
interface IAlgebraPool is
  IAlgebraPoolImmutables,
  IAlgebraPoolState,
  IAlgebraPoolDerivedState,
  IAlgebraPoolActions,
  IAlgebraPoolPermissionedActions,
  IAlgebraPoolEvents
{
  // used only for combining interfaces
}
          

@cryptoalgebra/core/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(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(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 fee The fee in hundredths of a bip, i.e. 1e-6
  function getFee(uint32 time, int24 tick, uint16 index, uint128 liquidity) external view returns (uint16 fee);
}
          

@cryptoalgebra/core/contracts/interfaces/pool/IAlgebraPoolActions.sol

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

/// @title Permissionless pool actions
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolActions {
  /**
   * @notice Sets the initial price for the pool
   * @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value
   * @param price the initial sqrt price of the pool as a Q64.96
   */
  function initialize(uint160 price) external;

  /**
   * @notice Adds liquidity for the given recipient/bottomTick/topTick position
   * @dev The caller of this method receives a callback in the form of IAlgebraMintCallback# AlgebraMintCallback
   * in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends
   * on bottomTick, topTick, the amount of liquidity, and the current price.
   * @param sender The address which will receive potential surplus of paid tokens
   * @param recipient The address for which the liquidity will be created
   * @param bottomTick The lower tick of the position in which to add liquidity
   * @param topTick The upper tick of the position in which to add liquidity
   * @param amount The desired amount of liquidity to mint
   * @param data Any data that should be passed through to the callback
   * @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback
   * @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback
   * @return liquidityActual The actual minted amount of liquidity
   */
  function mint(
    address sender,
    address recipient,
    int24 bottomTick,
    int24 topTick,
    uint128 amount,
    bytes calldata data
  )
    external
    returns (
      uint256 amount0,
      uint256 amount1,
      uint128 liquidityActual
    );

  /**
   * @notice Collects tokens owed to a position
   * @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.
   * Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or
   * amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the
   * actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.
   * @param recipient The address which should receive the fees collected
   * @param bottomTick The lower tick of the position for which to collect fees
   * @param topTick The upper tick of the position for which to collect fees
   * @param amount0Requested How much token0 should be withdrawn from the fees owed
   * @param amount1Requested How much token1 should be withdrawn from the fees owed
   * @return amount0 The amount of fees collected in token0
   * @return amount1 The amount of fees collected in token1
   */
  function collect(
    address recipient,
    int24 bottomTick,
    int24 topTick,
    uint128 amount0Requested,
    uint128 amount1Requested
  ) external returns (uint128 amount0, uint128 amount1);

  /**
   * @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position
   * @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0
   * @dev Fees must be collected separately via a call to #collect
   * @param bottomTick The lower tick of the position for which to burn liquidity
   * @param topTick The upper tick of the position for which to burn liquidity
   * @param amount How much liquidity to burn
   * @return amount0 The amount of token0 sent to the recipient
   * @return amount1 The amount of token1 sent to the recipient
   */
  function burn(
    int24 bottomTick,
    int24 topTick,
    uint128 amount
  ) external returns (uint256 amount0, uint256 amount1);

  /**
   * @notice Swap token0 for token1, or token1 for token0
   * @dev The caller of this method receives a callback in the form of IAlgebraSwapCallback# AlgebraSwapCallback
   * @param recipient The address to receive the output of the swap
   * @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0
   * @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
   * @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
   * value after the swap. If one for zero, the price cannot be greater than this value after the swap
   * @param data Any data to be passed through to the callback. If using the Router it should contain
   * SwapRouter#SwapCallbackData
   * @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
   * @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
   */
  function swap(
    address recipient,
    bool zeroToOne,
    int256 amountSpecified,
    uint160 limitSqrtPrice,
    bytes calldata data
  ) external returns (int256 amount0, int256 amount1);

  /**
   * @notice Swap token0 for token1, or token1 for token0 (tokens that have fee on transfer)
   * @dev The caller of this method receives a callback in the form of I AlgebraSwapCallback# AlgebraSwapCallback
   * @param sender The address called this function (Comes from the Router)
   * @param recipient The address to receive the output of the swap
   * @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0
   * @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
   * @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
   * value after the swap. If one for zero, the price cannot be greater than this value after the swap
   * @param data Any data to be passed through to the callback. If using the Router it should contain
   * SwapRouter#SwapCallbackData
   * @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
   * @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
   */
  function swapSupportingFeeOnInputTokens(
    address sender,
    address recipient,
    bool zeroToOne,
    int256 amountSpecified,
    uint160 limitSqrtPrice,
    bytes calldata data
  ) external returns (int256 amount0, int256 amount1);

  /**
   * @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback
   * @dev The caller of this method receives a callback in the form of IAlgebraFlashCallback# AlgebraFlashCallback
   * @dev All excess tokens paid in the callback are distributed to liquidity providers as an additional fee. So this method can be used
   * to donate underlying tokens to currently in-range liquidity providers by calling with 0 amount{0,1} and sending
   * the donation amount(s) from the callback
   * @param recipient The address which will receive the token0 and token1 amounts
   * @param amount0 The amount of token0 to send
   * @param amount1 The amount of token1 to send
   * @param data Any data to be passed through to the callback
   */
  function flash(
    address recipient,
    uint256 amount0,
    uint256 amount1,
    bytes calldata data
  ) external;
}
          

@cryptoalgebra/core/contracts/interfaces/pool/IAlgebraPoolDerivedState.sol

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

/**
 * @title Pool state that is not stored
 * @notice Contains view functions to provide information about the pool that is computed rather than stored on the
 * blockchain. The functions here may have variable gas costs.
 * @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
 * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
 */
interface IAlgebraPoolDerivedState {
  /**
   * @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp
   * @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing
   * the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,
   * you must call it with secondsAgos = [3600, 0].
   * @dev The time weighted average tick represents the geometric time weighted average price of the pool, in
   * log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.
   * @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned
   * @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp
   * @return secondsPerLiquidityCumulatives Cumulative seconds per liquidity-in-range value as of each `secondsAgos`
   * from the current block timestamp
   * @return volatilityCumulatives Cumulative standard deviation as of each `secondsAgos`
   * @return volumePerAvgLiquiditys Cumulative swap volume per liquidity as of each `secondsAgos`
   */
  function getTimepoints(uint32[] calldata secondsAgos)
    external
    view
    returns (
      int56[] memory tickCumulatives,
      uint160[] memory secondsPerLiquidityCumulatives,
      uint112[] memory volatilityCumulatives,
      uint256[] memory volumePerAvgLiquiditys
    );

  /**
   * @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range
   * @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.
   * I.e., snapshots cannot be compared if a position is not held for the entire period between when the first
   * snapshot is taken and the second snapshot is taken.
   * @param bottomTick The lower tick of the range
   * @param topTick The upper tick of the range
   * @return innerTickCumulative The snapshot of the tick accumulator for the range
   * @return innerSecondsSpentPerLiquidity The snapshot of seconds per liquidity for the range
   * @return innerSecondsSpent The snapshot of the number of seconds during which the price was in this range
   */
  function getInnerCumulatives(int24 bottomTick, int24 topTick)
    external
    view
    returns (
      int56 innerTickCumulative,
      uint160 innerSecondsSpentPerLiquidity,
      uint32 innerSecondsSpent
    );
}
          

@cryptoalgebra/core/contracts/interfaces/pool/IAlgebraPoolEvents.sol

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

/// @title Events emitted by a pool
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolEvents {
  /**
   * @notice Emitted exactly once by a pool when #initialize is first called on the pool
   * @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize
   * @param price The initial sqrt price of the pool, as a Q64.96
   * @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool
   */
  event Initialize(uint160 price, int24 tick);

  /**
   * @notice Emitted when liquidity is minted for a given position
   * @param sender The address that minted the liquidity
   * @param owner The owner of the position and recipient of any minted liquidity
   * @param bottomTick The lower tick of the position
   * @param topTick The upper tick of the position
   * @param liquidityAmount The amount of liquidity minted to the position range
   * @param amount0 How much token0 was required for the minted liquidity
   * @param amount1 How much token1 was required for the minted liquidity
   */
  event Mint(
    address sender,
    address indexed owner,
    int24 indexed bottomTick,
    int24 indexed topTick,
    uint128 liquidityAmount,
    uint256 amount0,
    uint256 amount1
  );

  /**
   * @notice Emitted when fees are collected by the owner of a position
   * @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees
   * @param owner The owner of the position for which fees are collected
   * @param recipient The address that received fees
   * @param bottomTick The lower tick of the position
   * @param topTick The upper tick of the position
   * @param amount0 The amount of token0 fees collected
   * @param amount1 The amount of token1 fees collected
   */
  event Collect(address indexed owner, address recipient, int24 indexed bottomTick, int24 indexed topTick, uint128 amount0, uint128 amount1);

  /**
   * @notice Emitted when a position's liquidity is removed
   * @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect
   * @param owner The owner of the position for which liquidity is removed
   * @param bottomTick The lower tick of the position
   * @param topTick The upper tick of the position
   * @param liquidityAmount The amount of liquidity to remove
   * @param amount0 The amount of token0 withdrawn
   * @param amount1 The amount of token1 withdrawn
   */
  event Burn(address indexed owner, int24 indexed bottomTick, int24 indexed topTick, uint128 liquidityAmount, uint256 amount0, uint256 amount1);

  /**
   * @notice Emitted by the pool for any swaps between token0 and token1
   * @param sender The address that initiated the swap call, and that received the callback
   * @param recipient The address that received the output of the swap
   * @param amount0 The delta of the token0 balance of the pool
   * @param amount1 The delta of the token1 balance of the pool
   * @param price The sqrt(price) of the pool after the swap, as a Q64.96
   * @param liquidity The liquidity of the pool after the swap
   * @param tick The log base 1.0001 of price of the pool after the swap
   */
  event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 price, uint128 liquidity, int24 tick);

  /**
   * @notice Emitted by the pool for any flashes of token0/token1
   * @param sender The address that initiated the swap call, and that received the callback
   * @param recipient The address that received the tokens from flash
   * @param amount0 The amount of token0 that was flashed
   * @param amount1 The amount of token1 that was flashed
   * @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee
   * @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee
   */
  event Flash(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1, uint256 paid0, uint256 paid1);

  /**
   * @notice Emitted when the community fee is changed by the pool
   * @param communityFee0New The updated value of the token0 community fee percent
   * @param communityFee1New The updated value of the token1 community fee percent
   */
  event CommunityFee(uint8 communityFee0New, uint8 communityFee1New);

  /**
   * @notice Emitted when the tick spacing changes
   * @param newTickSpacing The updated value of the new tick spacing
   */
  event TickSpacing(int24 newTickSpacing);

  /**
   * @notice Emitted when new activeIncentive is set
   * @param virtualPoolAddress The address of a virtual pool associated with the current active incentive
   */
  event Incentive(address indexed virtualPoolAddress);

  /**
   * @notice Emitted when the fee changes
   * @param fee The value of the token fee
   */
  event Fee(uint16 fee);

  /**
   * @notice Emitted when the LiquidityCooldown changes
   * @param liquidityCooldown The value of locktime for added liquidity
   */
  event LiquidityCooldown(uint32 liquidityCooldown);
}
          

@cryptoalgebra/core/contracts/interfaces/pool/IAlgebraPoolImmutables.sol

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

import '../IDataStorageOperator.sol';

/// @title Pool state that never changes
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolImmutables {
  /**
   * @notice The contract that stores all the timepoints and can perform actions with them
   * @return The operator address
   */
  function dataStorageOperator() external view returns (address);

  /**
   * @notice The contract that deployed the pool, which must adhere to the IAlgebraFactory interface
   * @return The contract address
   */
  function factory() external view returns (address);

  /**
   * @notice The first of the two tokens of the pool, sorted by address
   * @return The token contract address
   */
  function token0() external view returns (address);

  /**
   * @notice The second of the two tokens of the pool, sorted by address
   * @return The token contract address
   */
  function token1() external view returns (address);

  /**
   * @notice The maximum amount of position liquidity that can use any tick in the range
   * @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and
   * also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
   * @return The max amount of liquidity per tick
   */
  function maxLiquidityPerTick() external view returns (uint128);
}
          

@cryptoalgebra/core/contracts/interfaces/pool/IAlgebraPoolPermissionedActions.sol

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

/**
 * @title Permissioned pool actions
 * @notice Contains pool methods that may only be called by the factory owner or tokenomics
 * @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
 * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
 */
interface IAlgebraPoolPermissionedActions {
  /**
   * @notice Set the community's % share of the fees. Cannot exceed 25% (250)
   * @param communityFee0 new community fee percent for token0 of the pool in thousandths (1e-3)
   * @param communityFee1 new community fee percent for token1 of the pool in thousandths (1e-3)
   */
  function setCommunityFee(uint8 communityFee0, uint8 communityFee1) external;

  /// @notice Set the new tick spacing values. Only factory owner
  /// @param newTickSpacing The new tick spacing value
  function setTickSpacing(int24 newTickSpacing) external;

  /**
   * @notice Sets an active incentive
   * @param virtualPoolAddress The address of a virtual pool associated with the incentive
   */
  function setIncentive(address virtualPoolAddress) external;

  /**
   * @notice Sets new lock time for added liquidity
   * @param newLiquidityCooldown The time in seconds
   */
  function setLiquidityCooldown(uint32 newLiquidityCooldown) external;
}
          

@cryptoalgebra/core/contracts/interfaces/pool/IAlgebraPoolState.sol

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

/// @title Pool state that can change
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolState {
  /**
   * @notice The globalState structure in the pool stores many values but requires only one slot
   * and is exposed as a single method to save gas when accessed externally.
   * @return price The current price of the pool as a sqrt(token1/token0) Q64.96 value;
   * Returns tick The current tick of the pool, i.e. according to the last tick transition that was run;
   * Returns This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(price) if the price is on a tick
   * boundary;
   * Returns fee The last pool fee value in hundredths of a bip, i.e. 1e-6;
   * Returns timepointIndex The index of the last written timepoint;
   * Returns communityFeeToken0 The community fee percentage of the swap fee in thousandths (1e-3) for token0;
   * Returns communityFeeToken1 The community fee percentage of the swap fee in thousandths (1e-3) for token1;
   * Returns unlocked Whether the pool is currently locked to reentrancy;
   */
  function globalState()
    external
    view
    returns (
      uint160 price,
      int24 tick,
      uint16 fee,
      uint16 timepointIndex,
      uint8 communityFeeToken0,
      uint8 communityFeeToken1,
      bool unlocked
    );

  /**
   * @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool
   * @dev This value can overflow the uint256
   */
  function totalFeeGrowth0Token() external view returns (uint256);

  /**
   * @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool
   * @dev This value can overflow the uint256
   */
  function totalFeeGrowth1Token() external view returns (uint256);

  /**
   * @notice The currently in range liquidity available to the pool
   * @dev This value has no relationship to the total liquidity across all ticks.
   * Returned value cannot exceed type(uint128).max
   */
  function liquidity() external view returns (uint128);

  /**
   * @notice Look up information about a specific tick in the pool
   * @dev This is a public structure, so the `return` natspec tags are omitted.
   * @param tick The tick to look up
   * @return liquidityTotal the total amount of position liquidity that uses the pool either as tick lower or
   * tick upper;
   * Returns liquidityDelta how much liquidity changes when the pool price crosses the tick;
   * Returns outerFeeGrowth0Token the fee growth on the other side of the tick from the current tick in token0;
   * Returns outerFeeGrowth1Token the fee growth on the other side of the tick from the current tick in token1;
   * Returns outerTickCumulative the cumulative tick value on the other side of the tick from the current tick;
   * Returns outerSecondsPerLiquidity the seconds spent per liquidity on the other side of the tick from the current tick;
   * Returns outerSecondsSpent the seconds spent on the other side of the tick from the current tick;
   * Returns initialized Set to true if the tick is initialized, i.e. liquidityTotal is greater than 0
   * otherwise equal to false. Outside values can only be used if the tick is initialized.
   * In addition, these values are only relative and must be used only in comparison to previous snapshots for
   * a specific position.
   */
  function ticks(int24 tick)
    external
    view
    returns (
      uint128 liquidityTotal,
      int128 liquidityDelta,
      uint256 outerFeeGrowth0Token,
      uint256 outerFeeGrowth1Token,
      int56 outerTickCumulative,
      uint160 outerSecondsPerLiquidity,
      uint32 outerSecondsSpent,
      bool initialized
    );

  /** @notice Returns 256 packed tick initialized boolean values. See TickTable for more information */
  function tickTable(int16 wordPosition) external view returns (uint256);

  /**
   * @notice Returns the information about a position by the position's key
   * @dev This is a public mapping of structures, so the `return` natspec tags are omitted.
   * @param key The position's key is a hash of a preimage composed by the owner, bottomTick and topTick
   * @return liquidityAmount The amount of liquidity in the position;
   * Returns lastLiquidityAddTimestamp Timestamp of last adding of liquidity;
   * Returns innerFeeGrowth0Token Fee growth of token0 inside the tick range as of the last mint/burn/poke;
   * Returns innerFeeGrowth1Token Fee growth of token1 inside the tick range as of the last mint/burn/poke;
   * Returns fees0 The computed amount of token0 owed to the position as of the last mint/burn/poke;
   * Returns fees1 The computed amount of token1 owed to the position as of the last mint/burn/poke
   */
  function positions(bytes32 key)
    external
    view
    returns (
      uint128 liquidityAmount,
      uint32 lastLiquidityAddTimestamp,
      uint256 innerFeeGrowth0Token,
      uint256 innerFeeGrowth1Token,
      uint128 fees0,
      uint128 fees1
    );

  /**
   * @notice Returns data about a specific timepoint index
   * @param index The element of the timepoints array to fetch
   * @dev You most likely want to use #getTimepoints() instead of this method to get an timepoint as of some amount of time
   * ago, rather than at a specific index in the array.
   * This is a public mapping of structures, so the `return` natspec tags are omitted.
   * @return initialized whether the timepoint has been initialized and the values are safe to use;
   * Returns blockTimestamp The timestamp of the timepoint;
   * Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the timepoint timestamp;
   * Returns secondsPerLiquidityCumulative the seconds per in range liquidity for the life of the pool as of the timepoint timestamp;
   * Returns volatilityCumulative Cumulative standard deviation for the life of the pool as of the timepoint timestamp;
   * Returns averageTick Time-weighted average tick;
   * Returns 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 Returns the information about active incentive
   * @dev if there is no active incentive at the moment, virtualPool,endTimestamp,startTimestamp would be equal to 0
   * @return virtualPool The address of a virtual pool associated with the current active incentive
   */
  function activeIncentive() external view returns (address virtualPool);

  /**
   * @notice Returns the lock time for added liquidity
   */
  function liquidityCooldown() external view returns (uint32 cooldownInSeconds);

  /**
   * @notice The pool tick spacing
   * @dev Ticks can only be used at multiples of this value
   * e.g.: a tickSpacing of 60 means ticks can be initialized every 60th tick, i.e., ..., -120, -60, 0, 60, 120, ...
   * This value is an int24 to avoid casting even though it is always positive.
   * @return The tick spacing
   */
  function tickSpacing() external view returns (int24);
}
          

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

@cryptoalgebra/core/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;
}
          

@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Context_init_unchained();
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
    uint256[49] private __gap;
}
          

@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeaconUpgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967UpgradeUpgradeable is Initializable {
    function __ERC1967Upgrade_init() internal onlyInitializing {
        __ERC1967Upgrade_init_unchained();
    }

    function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
    }
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallSecure(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        address oldImplementation = _getImplementation();

        // Initial upgrade and setup call
        _setImplementation(newImplementation);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(newImplementation, data);
        }

        // Perform rollback test if not already in progress
        StorageSlotUpgradeable.BooleanSlot storage rollbackTesting = StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT);
        if (!rollbackTesting.value) {
            // Trigger rollback using upgradeTo from the new implementation
            rollbackTesting.value = true;
            _functionDelegateCall(
                newImplementation,
                abi.encodeWithSignature("upgradeTo(address)", oldImplementation)
            );
            rollbackTesting.value = false;
            // Check rollback was effective
            require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
            // Finally reset to the new implementation and log the upgrade
            _upgradeTo(newImplementation);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Emitted when the beacon is upgraded.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
        }
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
        require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
    }
    uint256[50] private __gap;
}
          

@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeaconUpgradeable {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}
          

@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/utils/Initializable.sol)

pragma solidity ^0.8.0;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
 * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() initializer {}
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        // If the contract is initializing we ignore whether _initialized is set in order to support multiple
        // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
        // contract may have been reentered.
        require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} modifier, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    function _isConstructor() private view returns (bool) {
        return !AddressUpgradeable.isContract(address(this));
    }
}
          

@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.0;

import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is Initializable, ERC1967UpgradeUpgradeable {
    function __UUPSUpgradeable_init() internal onlyInitializing {
        __ERC1967Upgrade_init_unchained();
        __UUPSUpgradeable_init_unchained();
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
    address private immutable __self = address(this);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        require(address(this) != __self, "Function must be called through delegatecall");
        require(_getImplementation() == __self, "Function must be called through active proxy");
        _;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeTo(address newImplementation) external virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallSecure(newImplementation, new bytes(0), false);
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallSecure(newImplementation, data, true);
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeTo} and {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal override onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;
    uint256[50] private __gap;
}
          

@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}
          

@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
        __Context_init_unchained();
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
    uint256[50] private __gap;
}
          

@openzeppelin/contracts-upgradeable/utils/StorageSlotUpgradeable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlotUpgradeable {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly {
            r.slot := slot
        }
    }
}
          

@openzeppelin/contracts/token/ERC20/IERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
          

@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol

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

import './pool/IUniswapV3PoolImmutables.sol';
import './pool/IUniswapV3PoolState.sol';
import './pool/IUniswapV3PoolDerivedState.sol';
import './pool/IUniswapV3PoolActions.sol';
import './pool/IUniswapV3PoolOwnerActions.sol';
import './pool/IUniswapV3PoolEvents.sol';

/// @title The interface for a Uniswap V3 Pool
/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform
/// to the ERC20 specification
/// @dev The pool interface is broken up into many smaller pieces
interface IUniswapV3Pool is
    IUniswapV3PoolImmutables,
    IUniswapV3PoolState,
    IUniswapV3PoolDerivedState,
    IUniswapV3PoolActions,
    IUniswapV3PoolOwnerActions,
    IUniswapV3PoolEvents
{

}
          

@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolActions.sol

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

/// @title Permissionless pool actions
/// @notice Contains pool methods that can be called by anyone
interface IUniswapV3PoolActions {
    /// @notice Sets the initial price for the pool
    /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value
    /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96
    function initialize(uint160 sqrtPriceX96) external;

    /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position
    /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback
    /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends
    /// on tickLower, tickUpper, the amount of liquidity, and the current price.
    /// @param recipient The address for which the liquidity will be created
    /// @param tickLower The lower tick of the position in which to add liquidity
    /// @param tickUpper The upper tick of the position in which to add liquidity
    /// @param amount The amount of liquidity to mint
    /// @param data Any data that should be passed through to the callback
    /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback
    /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback
    function mint(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount,
        bytes calldata data
    ) external returns (uint256 amount0, uint256 amount1);

    /// @notice Collects tokens owed to a position
    /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.
    /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or
    /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the
    /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.
    /// @param recipient The address which should receive the fees collected
    /// @param tickLower The lower tick of the position for which to collect fees
    /// @param tickUpper The upper tick of the position for which to collect fees
    /// @param amount0Requested How much token0 should be withdrawn from the fees owed
    /// @param amount1Requested How much token1 should be withdrawn from the fees owed
    /// @return amount0 The amount of fees collected in token0
    /// @return amount1 The amount of fees collected in token1
    function collect(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount0Requested,
        uint128 amount1Requested
    ) external returns (uint128 amount0, uint128 amount1);

    /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position
    /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0
    /// @dev Fees must be collected separately via a call to #collect
    /// @param tickLower The lower tick of the position for which to burn liquidity
    /// @param tickUpper The upper tick of the position for which to burn liquidity
    /// @param amount How much liquidity to burn
    /// @return amount0 The amount of token0 sent to the recipient
    /// @return amount1 The amount of token1 sent to the recipient
    function burn(
        int24 tickLower,
        int24 tickUpper,
        uint128 amount
    ) external returns (uint256 amount0, uint256 amount1);

    /// @notice Swap token0 for token1, or token1 for token0
    /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback
    /// @param recipient The address to receive the output of the swap
    /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0
    /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
    /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
    /// value after the swap. If one for zero, the price cannot be greater than this value after the swap
    /// @param data Any data to be passed through to the callback
    /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
    /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
    function swap(
        address recipient,
        bool zeroForOne,
        int256 amountSpecified,
        uint160 sqrtPriceLimitX96,
        bytes calldata data
    ) external returns (int256 amount0, int256 amount1);

    /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback
    /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback
    /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling
    /// with 0 amount{0,1} and sending the donation amount(s) from the callback
    /// @param recipient The address which will receive the token0 and token1 amounts
    /// @param amount0 The amount of token0 to send
    /// @param amount1 The amount of token1 to send
    /// @param data Any data to be passed through to the callback
    function flash(
        address recipient,
        uint256 amount0,
        uint256 amount1,
        bytes calldata data
    ) external;

    /// @notice Increase the maximum number of price and liquidity observations that this pool will store
    /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to
    /// the input observationCardinalityNext.
    /// @param observationCardinalityNext The desired minimum number of observations for the pool to store
    function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;
}
          

@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolDerivedState.sol

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

/// @title Pool state that is not stored
/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the
/// blockchain. The functions here may have variable gas costs.
interface IUniswapV3PoolDerivedState {
    /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp
    /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing
    /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,
    /// you must call it with secondsAgos = [3600, 0].
    /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in
    /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.
    /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned
    /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp
    /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block
    /// timestamp
    function observe(uint32[] calldata secondsAgos)
        external
        view
        returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);

    /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range
    /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.
    /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first
    /// snapshot is taken and the second snapshot is taken.
    /// @param tickLower The lower tick of the range
    /// @param tickUpper The upper tick of the range
    /// @return tickCumulativeInside The snapshot of the tick accumulator for the range
    /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range
    /// @return secondsInside The snapshot of seconds per liquidity for the range
    function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)
        external
        view
        returns (
            int56 tickCumulativeInside,
            uint160 secondsPerLiquidityInsideX128,
            uint32 secondsInside
        );
}
          

@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolEvents.sol

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

/// @title Events emitted by a pool
/// @notice Contains all events emitted by the pool
interface IUniswapV3PoolEvents {
    /// @notice Emitted exactly once by a pool when #initialize is first called on the pool
    /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize
    /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96
    /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool
    event Initialize(uint160 sqrtPriceX96, int24 tick);

    /// @notice Emitted when liquidity is minted for a given position
    /// @param sender The address that minted the liquidity
    /// @param owner The owner of the position and recipient of any minted liquidity
    /// @param tickLower The lower tick of the position
    /// @param tickUpper The upper tick of the position
    /// @param amount The amount of liquidity minted to the position range
    /// @param amount0 How much token0 was required for the minted liquidity
    /// @param amount1 How much token1 was required for the minted liquidity
    event Mint(
        address sender,
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 amount,
        uint256 amount0,
        uint256 amount1
    );

    /// @notice Emitted when fees are collected by the owner of a position
    /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees
    /// @param owner The owner of the position for which fees are collected
    /// @param tickLower The lower tick of the position
    /// @param tickUpper The upper tick of the position
    /// @param amount0 The amount of token0 fees collected
    /// @param amount1 The amount of token1 fees collected
    event Collect(
        address indexed owner,
        address recipient,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 amount0,
        uint128 amount1
    );

    /// @notice Emitted when a position's liquidity is removed
    /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect
    /// @param owner The owner of the position for which liquidity is removed
    /// @param tickLower The lower tick of the position
    /// @param tickUpper The upper tick of the position
    /// @param amount The amount of liquidity to remove
    /// @param amount0 The amount of token0 withdrawn
    /// @param amount1 The amount of token1 withdrawn
    event Burn(
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 amount,
        uint256 amount0,
        uint256 amount1
    );

    /// @notice Emitted by the pool for any swaps between token0 and token1
    /// @param sender The address that initiated the swap call, and that received the callback
    /// @param recipient The address that received the output of the swap
    /// @param amount0 The delta of the token0 balance of the pool
    /// @param amount1 The delta of the token1 balance of the pool
    /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96
    /// @param liquidity The liquidity of the pool after the swap
    /// @param tick The log base 1.0001 of price of the pool after the swap
    event Swap(
        address indexed sender,
        address indexed recipient,
        int256 amount0,
        int256 amount1,
        uint160 sqrtPriceX96,
        uint128 liquidity,
        int24 tick
    );

    /// @notice Emitted by the pool for any flashes of token0/token1
    /// @param sender The address that initiated the swap call, and that received the callback
    /// @param recipient The address that received the tokens from flash
    /// @param amount0 The amount of token0 that was flashed
    /// @param amount1 The amount of token1 that was flashed
    /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee
    /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee
    event Flash(
        address indexed sender,
        address indexed recipient,
        uint256 amount0,
        uint256 amount1,
        uint256 paid0,
        uint256 paid1
    );

    /// @notice Emitted by the pool for increases to the number of observations that can be stored
    /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index
    /// just before a mint/swap/burn.
    /// @param observationCardinalityNextOld The previous value of the next observation cardinality
    /// @param observationCardinalityNextNew The updated value of the next observation cardinality
    event IncreaseObservationCardinalityNext(
        uint16 observationCardinalityNextOld,
        uint16 observationCardinalityNextNew
    );

    /// @notice Emitted when the protocol fee is changed by the pool
    /// @param feeProtocol0Old The previous value of the token0 protocol fee
    /// @param feeProtocol1Old The previous value of the token1 protocol fee
    /// @param feeProtocol0New The updated value of the token0 protocol fee
    /// @param feeProtocol1New The updated value of the token1 protocol fee
    event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New);

    /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner
    /// @param sender The address that collects the protocol fees
    /// @param recipient The address that receives the collected protocol fees
    /// @param amount0 The amount of token0 protocol fees that is withdrawn
    /// @param amount0 The amount of token1 protocol fees that is withdrawn
    event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);
}
          

@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol

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

/// @title Pool state that never changes
/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values
interface IUniswapV3PoolImmutables {
    /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface
    /// @return The contract address
    function factory() external view returns (address);

    /// @notice The first of the two tokens of the pool, sorted by address
    /// @return The token contract address
    function token0() external view returns (address);

    /// @notice The second of the two tokens of the pool, sorted by address
    /// @return The token contract address
    function token1() external view returns (address);

    /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6
    /// @return The fee
    function fee() external view returns (uint24);

    /// @notice The pool tick spacing
    /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive
    /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...
    /// This value is an int24 to avoid casting even though it is always positive.
    /// @return The tick spacing
    function tickSpacing() external view returns (int24);

    /// @notice The maximum amount of position liquidity that can use any tick in the range
    /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and
    /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
    /// @return The max amount of liquidity per tick
    function maxLiquidityPerTick() external view returns (uint128);
}
          

@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolOwnerActions.sol

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

/// @title Permissioned pool actions
/// @notice Contains pool methods that may only be called by the factory owner
interface IUniswapV3PoolOwnerActions {
    /// @notice Set the denominator of the protocol's % share of the fees
    /// @param feeProtocol0 new protocol fee for token0 of the pool
    /// @param feeProtocol1 new protocol fee for token1 of the pool
    function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;

    /// @notice Collect the protocol fee accrued to the pool
    /// @param recipient The address to which collected protocol fees should be sent
    /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1
    /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0
    /// @return amount0 The protocol fee collected in token0
    /// @return amount1 The protocol fee collected in token1
    function collectProtocol(
        address recipient,
        uint128 amount0Requested,
        uint128 amount1Requested
    ) external returns (uint128 amount0, uint128 amount1);
}
          

@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol

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

/// @title Pool state that can change
/// @notice These methods compose the pool's state, and can change with any frequency including multiple times
/// per transaction
interface IUniswapV3PoolState {
    /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas
    /// when accessed externally.
    /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value
    /// tick The current tick of the pool, i.e. according to the last tick transition that was run.
    /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick
    /// boundary.
    /// observationIndex The index of the last oracle observation that was written,
    /// observationCardinality The current maximum number of observations stored in the pool,
    /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.
    /// feeProtocol The protocol fee for both tokens of the pool.
    /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0
    /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.
    /// unlocked Whether the pool is currently locked to reentrancy
    function slot0()
        external
        view
        returns (
            uint160 sqrtPriceX96,
            int24 tick,
            uint16 observationIndex,
            uint16 observationCardinality,
            uint16 observationCardinalityNext,
            uint8 feeProtocol,
            bool unlocked
        );

    /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool
    /// @dev This value can overflow the uint256
    function feeGrowthGlobal0X128() external view returns (uint256);

    /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool
    /// @dev This value can overflow the uint256
    function feeGrowthGlobal1X128() external view returns (uint256);

    /// @notice The amounts of token0 and token1 that are owed to the protocol
    /// @dev Protocol fees will never exceed uint128 max in either token
    function protocolFees() external view returns (uint128 token0, uint128 token1);

    /// @notice The currently in range liquidity available to the pool
    /// @dev This value has no relationship to the total liquidity across all ticks
    function liquidity() external view returns (uint128);

    /// @notice Look up information about a specific tick in the pool
    /// @param tick The tick to look up
    /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or
    /// tick upper,
    /// liquidityNet how much liquidity changes when the pool price crosses the tick,
    /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,
    /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,
    /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick
    /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,
    /// secondsOutside the seconds spent on the other side of the tick from the current tick,
    /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.
    /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.
    /// In addition, these values are only relative and must be used only in comparison to previous snapshots for
    /// a specific position.
    function ticks(int24 tick)
        external
        view
        returns (
            uint128 liquidityGross,
            int128 liquidityNet,
            uint256 feeGrowthOutside0X128,
            uint256 feeGrowthOutside1X128,
            int56 tickCumulativeOutside,
            uint160 secondsPerLiquidityOutsideX128,
            uint32 secondsOutside,
            bool initialized
        );

    /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information
    function tickBitmap(int16 wordPosition) external view returns (uint256);

    /// @notice Returns the information about a position by the position's key
    /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper
    /// @return _liquidity The amount of liquidity in the position,
    /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,
    /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,
    /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,
    /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke
    function positions(bytes32 key)
        external
        view
        returns (
            uint128 _liquidity,
            uint256 feeGrowthInside0LastX128,
            uint256 feeGrowthInside1LastX128,
            uint128 tokensOwed0,
            uint128 tokensOwed1
        );

    /// @notice Returns data about a specific observation index
    /// @param index The element of the observations array to fetch
    /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time
    /// ago, rather than at a specific index in the array.
    /// @return blockTimestamp The timestamp of the observation,
    /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,
    /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,
    /// Returns initialized whether the observation has been initialized and the values are safe to use
    function observations(uint256 index)
        external
        view
        returns (
            uint32 blockTimestamp,
            int56 tickCumulative,
            uint160 secondsPerLiquidityCumulativeX128,
            bool initialized
        );
}
          

contracts/interfaces/IBareVaultRegistry.sol

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

/**
 * Used only as a 0.7.6 registry for the UniLiquidityManager.
 */
interface IBareVaultRegistry {
    /**
     * PendingApproval: strategy is submitted but has not yet been approved by the owner
     * PendingThreshold: strategy is approved but has not yet reached the threshold of TVL required
     * Paused: strategy was active but something went wrong, so now it's paused
     * Active: strategy is active and can be used
     * Retired: strategy is retired and can no longer be used
     */
    enum VaultState {
        PendingApproval,
        PendingThreshold,
        Paused,
        Active,
        Retired
    }

    /**
     * @dev all necessary data for vault. Name and symbol are stored in vault's ERC20. Owner is stored with tokenId in StrategyRegistry.
     * tokenId: NFT identifier number
     * vaultAddress: address of vault this describes
     * state: state of the vault.
     */
    struct VaultData {
        VaultState state;
        uint256 tokenId; //NFT ownership of this vault and all others that use vault's exec bundle
        uint256 vaultID; //unique identifier for this vault and strategy token id
        string payloadIpfs;
        address vaultAddress;
        string beaconName;
    }

    /// @notice Retrieves the creator of a given vault
    /// @param _vault The address of the vault
    /// @return The address of the creator
    function getStrategyCreatorForVault(
        address _vault
    ) external view returns (address);

    //Total vault count
    function totalVaultCount() external view returns (uint256);

    function whitelistRegistry() external view returns (address);

    /// @dev Retrieves the details of a given vault by address
    /// @param _address The address of the vault
    /// @return The details of the vault
    function getVaultDetails(
        address _address
    ) external view returns (VaultData memory);

    function feeManager() external view returns (address);

    function vaultHelper() external view returns (address);

    function doISupportInterface(
        bytes4 interfaceId
    ) external view returns (bool);

    function owner() external view returns (address);
}
          

contracts/interfaces/IMultiPositionManager.sol

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.10;
pragma abicoder v2;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import { IAlgebraPool } from "@cryptoalgebra/core/contracts/interfaces/IAlgebraPool.sol";

interface IMultiPositionManager is IERC20 {
    struct VaultDetails {
        string vaultType;
        address token0;
        address token1;
        string name;
        string symbol;
        uint256 decimals;
        string token0Name;
        string token1Name;
        string token0Symbol;
        string token1Symbol;
        uint256 token0Decimals;
        uint256 token1Decimals;
        uint256 feeTier;
        uint256 totalLPTokensIssued;
        uint256 token0Balance;
        uint256 token1Balance;
        address vaultCreator;
    }

    struct AlgebraVaultDetails {
        string vaultType;
        address token0;
        address token1;
        string name;
        string symbol;
        uint256 decimals;
        string token0Name;
        string token1Name;
        string token0Symbol;
        string token1Symbol;
        uint256 token0Decimals;
        uint256 token1Decimals;
        uint256 totalLPTokensIssued;
        uint256 token0Balance;
        uint256 token1Balance;
        address vaultCreator;
    }

    struct VaultBalance {
        uint256 amountToken0;
        uint256 amountToken1;
    }

    struct LiquidityPositions {
        int24[] lowerTick;
        int24[] upperTick;
        uint16[] relativeWeight;
    }

    /**
     * @dev initializes vault
     * param _vaultManager is the address which will manage the vault being created
     * param _params is all other parameters this vault will use.
     * param _tokenName is the name of the LPT of this vault.
     * param _symbol is the symbol of the LPT of this vault.
     * param token0 is address of token0
     * param token1 is address of token1
     * param _FEE is pool fee, how much is charged for a swap
     */
    function initialize(
        address _vaultManager,
        address, //orchestrator not needed here as, if this vault is to be managed by orchestrator, _vaultManager parameter should be the orchestrator address
        address _steer,
        bytes memory _params
    ) external;

    ///
    /// @dev Deposits tokens in proportion to the vault's current holdings.
    /// @dev These tokens sit in the vault and are not used for liquidity on
    /// Uniswap until the next rebalance.
    /// @param amount0Desired Max amount of token0 to deposit
    /// @param amount1Desired Max amount of token1 to deposit
    /// @param amount0Min Revert if resulting `amount0` is less than this
    /// @param amount1Min Revert if resulting `amount1` is less than this
    /// @param to Recipient of shares
    /// @return shares Number of shares minted
    /// @return amount0 Amount of token0 deposited
    /// @return amount1 Amount of token1 deposited
    ///
    function deposit(
        uint256 amount0Desired,
        uint256 amount1Desired,
        uint256 amount0Min,
        uint256 amount1Min,
        address to
    ) external returns (uint256 shares, uint256 amount0, uint256 amount1);

    /**
     * @dev burns each vault position which contains liquidity, updating fees owed to that position.
     * @dev call this before calling getTotalAmounts if total amounts must include fees. There's a function in the periphery to do so through a static call.
     */
    function poke() external;

    /**
     * @dev Withdraws tokens in proportion to the vault's holdings.
     * @param shares Shares burned by sender
     * @param amount0Min Revert if resulting `amount0` is smaller than this
     * @param amount1Min Revert if resulting `amount1` is smaller than this
     * @param to Recipient of tokens
     * @return amount0 Amount of token0 sent to recipient
     * @return amount1 Amount of token1 sent to recipient
     */
    function withdraw(
        uint256 shares,
        uint256 amount0Min,
        uint256 amount1Min,
        address to
    ) external returns (uint256 amount0, uint256 amount1);

    /**
     * @dev Internal function to pull funds from pool, update positions if necessary, then deposit funds into pool.
     * @dev reverts if it does not have any liquidity.

     * @dev newPositions requirements:
     * Each lowerTick must be lower than its corresponding upperTick
     * Each lowerTick must be greater than or equal to the tick min (-887272)
     * Each upperTick must be less than or equal to the tick max (887272)
     * All lowerTicks and upperTicks must be divisible by the pool tickSpacing--
        A 0.05% fee pool has tick spacing of 10, 0.3% has tick spacing 60. and 1% has tick spacing 200.)
     */
    function tend(
        LiquidityPositions memory newPositions,
        int256 swapAmount,
        uint160 sqrtPriceLimitX96
    ) external;

    /**
     * @dev Calculates the vault's total holdings of token0 and token1 - in
     *      other words, how much of each token the vault would hold if it withdrew
     *      all its liquidity from Uniswap.
     * @dev this function DOES NOT include fees. To include fees, first poke() and then call getTotalAmounts. There's a function inside the periphery to do so.
     */
    function getTotalAmounts()
        external
        view
        returns (uint256 total0, uint256 total1);

    //Tokens
    function vaultRegistry() external view returns (address);

    function token0() external view returns (address);

    function token1() external view returns (address);

    function maxTotalSupply() external view returns (uint256);

    function pool() external view returns (IUniswapV3Pool);

    function TOTAL_FEE() external view returns (uint256);

    function STEER_FRACTION_OF_FEE() external view returns (uint256);

    function feeDetails()
        external
        view
        returns (uint256, address[] memory, string[] memory, uint256[] memory);

    // /**
    //  * @dev Used to collect accumulated protocol fees.
    //  */
    // function steerCollectFees(
    //     uint256 amount0,
    //     uint256 amount1,
    //     address to
    // ) external;

    // /**
    //  * @dev Used to collect accumulated protocol fees.
    //  */
    // function strategistCollectFees(
    //     uint256 amount0,
    //     uint256 amount1,
    //     address to
    // ) external;

    /**
     * @dev Used to collect accumulated protocol fees.
     */
    function collectFees(
        string memory feeIdentifier,
        uint256 amount0,
        uint256 amount1
    ) external;

    /**
     * @dev Removes liquidity in case of emergency.
     */
    function emergencyBurn(
        int24 tickLower,
        int24 tickUpper,
        uint128 liquidity
    ) external returns (uint256 amount0, uint256 amount1);

    function accruedFees0(string memory) external view returns (uint256);

    function accruedFees1(string memory) external view returns (uint256);
}
          

Compiler Settings

{"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":5,"enabled":true},"metadata":{"useLiteralContent":true,"bytecodeHash":"ipfs"},"libraries":{},"evmVersion":"paris"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"AdminChanged","inputs":[{"type":"address","name":"previousAdmin","internalType":"address","indexed":false},{"type":"address","name":"newAdmin","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"BeaconUpgraded","inputs":[{"type":"address","name":"beacon","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"FeeUpdated","inputs":[{"type":"address","name":"vault","internalType":"address","indexed":true},{"type":"string[]","name":"feeIdentifier","internalType":"string[]","indexed":false},{"type":"uint256[]","name":"feeValue","internalType":"uint256[]","indexed":false},{"type":"address[]","name":"withdrawer","internalType":"address[]","indexed":false}],"anonymous":false},{"type":"event","name":"FeeWithdrawn","inputs":[{"type":"address","name":"caller","internalType":"address","indexed":true},{"type":"address","name":"vault","internalType":"address","indexed":true},{"type":"string","name":"feeIdentifier","internalType":"string","indexed":false},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"amount0","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount1","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FeesWithdrawn","inputs":[{"type":"address","name":"caller","internalType":"address","indexed":true},{"type":"address","name":"vault","internalType":"address","indexed":false},{"type":"string[]","name":"feeIdentifier","internalType":"string[]","indexed":false},{"type":"address[]","name":"to","internalType":"address[]","indexed":false},{"type":"uint256[]","name":"amount0","internalType":"uint256[]","indexed":false},{"type":"uint256[]","name":"amount1","internalType":"uint256[]","indexed":false}],"anonymous":false},{"type":"event","name":"FeesWithdrawnFromMultipleVaults","inputs":[{"type":"address","name":"caller","internalType":"address","indexed":true},{"type":"address[]","name":"vaults","internalType":"address[]","indexed":false},{"type":"string[][]","name":"feeIdentifiers","internalType":"string[][]","indexed":false},{"type":"address[][]","name":"to","internalType":"address[][]","indexed":false},{"type":"uint256[][]","name":"amount0","internalType":"uint256[][]","indexed":false},{"type":"uint256[][]","name":"amount1","internalType":"uint256[][]","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"type":"address","name":"implementation","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"pure","outputs":[],"name":"areAllUnique","inputs":[{"type":"string[]","name":"stringArray","internalType":"string[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"changeFeeWithdrawer","inputs":[{"type":"address","name":"vault","internalType":"address"},{"type":"string","name":"feeIdentifier","internalType":"string"},{"type":"address","name":"newWithdrawer","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct FeeManager.Fee[]","components":[{"type":"string","name":"feeIdentifier","internalType":"string"},{"type":"uint256","name":"feeValue","internalType":"uint256"}]}],"name":"getFees","inputs":[{"type":"address","name":"vault","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_vaultRegistry","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDefaultFeeAndWithdrawalPermission","inputs":[{"type":"address","name":"vault","internalType":"address"},{"type":"uint256","name":"totalVaultFees","internalType":"uint256"},{"type":"string[]","name":"feeIdentifier","internalType":"string[]"},{"type":"uint256[]","name":"feeValue","internalType":"uint256[]"},{"type":"address[]","name":"withdrawer","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeAndWithdrawalPermission","inputs":[{"type":"address","name":"vault","internalType":"address"},{"type":"string[]","name":"feeIdentifier","internalType":"string[]"},{"type":"uint256[]","name":"feeValue","internalType":"uint256[]"},{"type":"address[]","name":"withdrawer","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMigratedVaultFeeAndWithdrawalPermission","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTotalFees","inputs":[{"type":"address","name":"vault","internalType":"address"},{"type":"uint256","name":"newTotalFees","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgradeTo","inputs":[{"type":"address","name":"newImplementation","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"upgradeToAndCall","inputs":[{"type":"address","name":"newImplementation","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"feeIdentifier","internalType":"string"},{"type":"uint256","name":"feeValue","internalType":"uint256"}],"name":"vaultFees","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"vaultRegistry","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"vaultTotalFees","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawFee","inputs":[{"type":"address","name":"vault","internalType":"address"},{"type":"string","name":"feeIdentifier","internalType":"string"},{"type":"uint256","name":"amount0","internalType":"uint256"},{"type":"uint256","name":"amount1","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawFeesFromMultipleVaults","inputs":[{"type":"address[]","name":"vaults","internalType":"address[]"},{"type":"string[][]","name":"feeIdentifiers","internalType":"string[][]"},{"type":"uint256[][]","name":"amount0","internalType":"uint256[][]"},{"type":"uint256[][]","name":"amount1","internalType":"uint256[][]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawMultipleFees","inputs":[{"type":"address","name":"vault","internalType":"address"},{"type":"string[]","name":"feeIdentifiers","internalType":"string[]"},{"type":"uint256[]","name":"amount0","internalType":"uint256[]"},{"type":"uint256[]","name":"amount1","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"withdrawalPermissions","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"string","name":"","internalType":"string"}]}]
              

Contract Creation Code

0x60a0604052306080523480156200001557600080fd5b50600054610100900460ff16620000335760005460ff16156200003d565b6200003d620000e2565b620000a55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b600054610100900460ff16158015620000c8576000805461ffff19166101011790555b8015620000db576000805461ff00191690555b5062000106565b6000620000fa306200010060201b6200299d1760201c565b15905090565b3b151590565b6080516140546200013760003960008181611a5101528181611a9101528181611c120152611c5201526140546000f3fe6080604052600436106100ef5760003560e01c806304e493fd146100f4578063130a19821461010b57806316828da81461012b578063249518e91461014b57806325d8456d1461016b5780633659cfe61461018b578063387024ac146101ab5780634f1ef286146101cb5780635376c803146101de578063715018a6146101fe5780638da5cb5b1461021357806390cfc4061461023e578063912cb891146102795780639af608c9146102a7578063bcc27dd9146102d4578063c4d66de8146102f4578063cdd7b38a14610314578063dece884d14610334578063f2fde38b14610354578063f3aefd5514610374575b600080fd5b34801561010057600080fd5b506101096103c6565b005b34801561011757600080fd5b506101096101263660046131ce565b610aae565b34801561013757600080fd5b506101096101463660046132e9565b611447565b34801561015757600080fd5b5061010961016636600461338d565b61171a565b34801561017757600080fd5b506101096101863660046133b9565b611787565b34801561019757600080fd5b506101096101a6366004613447565b611a47565b3480156101b757600080fd5b506101096101c6366004613464565b611b0f565b6101096101d93660046134a0565b611c08565b3480156101ea57600080fd5b506101096101f9366004613503565b611cbd565b34801561020a57600080fd5b50610109611f00565b34801561021f57600080fd5b50610228611f3b565b6040516102359190613562565b60405180910390f35b34801561024a57600080fd5b5061026b610259366004613447565b60ca6020526000908152604090205481565b604051908152602001610235565b34801561028557600080fd5b5061029961029436600461338d565b611f4a565b6040516102359291906135c6565b3480156102b357600080fd5b506102c76102c2366004613447565b612013565b60405161023591906135e8565b3480156102e057600080fd5b506101096102ef36600461365e565b612124565b34801561030057600080fd5b5061010961030f366004613447565b612215565b34801561032057600080fd5b5060cc54610228906001600160a01b031681565b34801561034057600080fd5b5061010961034f3660046136c1565b6122f9565b34801561036057600080fd5b5061010961036f366004613447565b612900565b34801561038057600080fd5b5061022861038f36600461374f565b60cb60209081526000928352604090922081518083018401805192815290840192909301919091209152546001600160a01b031681565b60cc546040516367a44ca360e01b815233916001600160a01b0316906367a44ca3906103f6908490600401613562565b600060405180830381865afa158015610413573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261043b91908101906137f8565b608001516001600160a01b03161461048e5760405162461bcd60e51b8152602060048201526011602482015270139bdd08104814dd19595c8815985d5b1d607a1b60448201526064015b60405180910390fd5b60408051600280825260608201909252600091816020015b60608152602001906001900390816104a65790505090506040518060400160405280600a81526020016953544545525f4645455360b01b815250816000815181106104f3576104f36138be565b60200260200101819052506040518060400160405280600f81526020016e535452415445474953545f4645455360881b81525081600181518110610539576105396138be565b602090810291909101015260408051600280825260608201909252600091816020016020820280368337019050509050336001600160a01b0316631c1f19366040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cb91906138d4565b816000815181106105de576105de6138be565b602002602001018181525050806000815181106105fd576105fd6138be565b60200260200101516127106106129190613903565b81600181518110610625576106256138be565b602090810291909101015260408051600280825260608201909252600091816020016020820280368337505060cc5460408051638da5cb5b60e01b815290519394506001600160a01b0390911692638da5cb5b925060048083019260209291908290030181865afa15801561069e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c29190613916565b816000815181106106d5576106d56138be565b6001600160a01b03928316602091820292909201015260cc5460405163015a1d6760e31b8152911690630ad0eb3890610712903390600401613562565b602060405180830381865afa15801561072f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107539190613916565b81600181518110610766576107666138be565b60200260200101906001600160a01b031690816001600160a01b0316815250506000336001600160a01b03166363db7eae6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ea91906138d4565b905061271081111561080e5760405162461bcd60e51b815260040161048590613933565b33600090815260c96020526040808220815180830190925286519092829188919061083b5761083b6138be565b602002602001015181526020018560008151811061085b5761085b6138be565b602090810291909101810151909152825460018101845560009384529220815191926002020190819061088e90826139e8565b5060208201518160010155505060c96000336001600160a01b03166001600160a01b031681526020019081526020016000206040518060400160405280866001815181106108de576108de6138be565b60200260200101518152602001856001815181106108fe576108fe6138be565b602090810291909101810151909152825460018101845560009384529220815191926002020190819061093190826139e8565b5060208201518160010155505081600081518110610951576109516138be565b602002602001015160cb6000336001600160a01b03166001600160a01b0316815260200190815260200160002085600081518110610991576109916138be565b60200260200101516040516109a69190613aa7565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001815181106109eb576109eb6138be565b602002602001015160cb6000336001600160a01b03166001600160a01b0316815260200190815260200160002085600181518110610a2b57610a2b6138be565b6020026020010151604051610a409190613aa7565b908152604080516020928190038301812080546001600160a01b0319166001600160a01b03959095169490941790935533600081815260ca909352912083905590600080516020613fff83398151915290610aa090879087908790613b8c565b60405180910390a250505050565b82518451148015610ac0575081518451145b8015610acd575080518451145b610b145760405162461bcd60e51b8152602060048201526018602482015277082e4e4c2f240d8cadccee8d0e640daeae6e840dac2e8c6d60431b6044820152606401610485565b600084516001600160401b03811115610b2f57610b2f612edb565b604051908082528060200260200182016040528015610b6257816020015b6060815260200190600190039081610b4d5790505b509050600085516001600160401b03811115610b8057610b80612edb565b604051908082528060200260200182016040528015610bb357816020015b6060815260200190600190039081610b9e5790505b509050600086516001600160401b03811115610bd157610bd1612edb565b604051908082528060200260200182016040528015610c0457816020015b6060815260200190600190039081610bef5790505b50905060005b87518110156113f4576000888281518110610c2757610c276138be565b602002602001015190506000888381518110610c4557610c456138be565b60200260200101519050600081519050806001600160401b03811115610c6d57610c6d612edb565b604051908082528060200260200182016040528015610c96578160200160208202803683370190505b50878581518110610ca957610ca96138be565b6020026020010181905250806001600160401b03811115610ccc57610ccc612edb565b604051908082528060200260200182016040528015610cf5578160200160208202803683370190505b50868581518110610d0857610d086138be565b6020026020010181905250806001600160401b03811115610d2b57610d2b612edb565b604051908082528060200260200182016040528015610d54578160200160208202803683370190505b50858581518110610d6757610d676138be565b60200260200101819052506000898581518110610d8657610d866138be565b6020026020010151511180610db557506000888581518110610daa57610daa6138be565b602002602001015151115b156110cd5780898581518110610dcd57610dcd6138be565b602002602001015151148015610dfc575080888581518110610df157610df16138be565b602002602001015151145b610e585760405162461bcd60e51b815260206004820152602760248201527f416d6f756e747320616e64204964656e74696669657273206c656e677468206d6044820152660d2e6dac2e8c6d60cb1b6064820152608401610485565b60005b818110156110c7576001600160a01b038416600090815260cb602052604090208351849083908110610e8f57610e8f6138be565b6020026020010151604051610ea49190613aa7565b9081526040519081900360200190205488516001600160a01b0390911690899087908110610ed457610ed46138be565b60200260200101518281518110610eed57610eed6138be565b60200260200101906001600160a01b031690816001600160a01b031681525050836001600160a01b0316638ec4daf6848381518110610f2e57610f2e6138be565b60200260200101518c8881518110610f4857610f486138be565b60200260200101518481518110610f6157610f616138be565b60200260200101518c8981518110610f7b57610f7b6138be565b60200260200101518581518110610f9457610f946138be565b60200260200101516040518463ffffffff1660e01b8152600401610fba93929190613bcf565b600060405180830381600087803b158015610fd457600080fd5b505af1158015610fe8573d6000803e3d6000fd5b50505050898581518110610ffe57610ffe6138be565b60200260200101518181518110611017576110176138be565b6020026020010151878681518110611031576110316138be565b6020026020010151828151811061104a5761104a6138be565b602002602001018181525050888581518110611068576110686138be565b60200260200101518181518110611081576110816138be565b602002602001015186868151811061109b5761109b6138be565b602002602001015182815181106110b4576110b46138be565b6020908102919091010152600101610e5b565b506113e9565b60005b818110156113e7576001600160a01b038416600090815260cb602052604090208351849083908110611104576111046138be565b60200260200101516040516111199190613aa7565b9081526040519081900360200190205488516001600160a01b0390911690899087908110611149576111496138be565b60200260200101518281518110611162576111626138be565b60200260200101906001600160a01b031690816001600160a01b031681525050836001600160a01b0316633bec034a8483815181106111a3576111a36138be565b60200260200101516040518263ffffffff1660e01b81526004016111c79190613bf4565b602060405180830381865afa1580156111e4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120891906138d4565b87868151811061121a5761121a6138be565b60200260200101518281518110611233576112336138be565b602002602001018181525050836001600160a01b031663b7ab45b6848381518110611260576112606138be565b60200260200101516040518263ffffffff1660e01b81526004016112849190613bf4565b602060405180830381865afa1580156112a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c591906138d4565b8686815181106112d7576112d76138be565b602002602001015182815181106112f0576112f06138be565b602002602001018181525050836001600160a01b0316638ec4daf684838151811061131d5761131d6138be565b6020026020010151898881518110611337576113376138be565b60200260200101518481518110611350576113506138be565b602002602001015189898151811061136a5761136a6138be565b60200260200101518581518110611383576113836138be565b60200260200101516040518463ffffffff1660e01b81526004016113a993929190613bcf565b600060405180830381600087803b1580156113c357600080fd5b505af11580156113d7573d6000803e3d6000fd5b5050600190920191506110d09050565b505b505050600101610c0a565b50336001600160a01b03167fee94e1b4e723a9d0391bc453bb49192fdb33320cbd8377328572e9d0966dc7a58888868686604051611436959493929190613c97565b60405180910390a250505050505050565b60cc546001600160a01b031633146114925760405162461bcd60e51b815260206004820152600e60248201526d215661756c74526567697374727960901b6044820152606401610485565b815183511480156114a4575080518251145b6114c05760405162461bcd60e51b815260040161048590613d46565b6114c983611b0f565b6127108411156114eb5760405162461bcd60e51b815260040161048590613933565b6000805b84518110156116ab5760006001600160a01b0316838281518110611515576115156138be565b60200260200101516001600160a01b0316036115435760405162461bcd60e51b815260040161048590613d8c565b60c96000886001600160a01b03166001600160a01b031681526020019081526020016000206040518060400160405280878481518110611585576115856138be565b602002602001015181526020018684815181106115a4576115a46138be565b60209081029190910181015190915282546001810184556000938452922081519192600202019081906115d790826139e8565b506020820151816001015550508281815181106115f6576115f66138be565b602002602001015160cb6000896001600160a01b03166001600160a01b03168152602001908152602001600020868381518110611635576116356138be565b602002602001015160405161164a9190613aa7565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555083818151811061168e5761168e6138be565b6020026020010151826116a19190613dcd565b91506001016114ef565b5080612710146116cd5760405162461bcd60e51b815260040161048590613de0565b6001600160a01b038616600081815260ca60205260409081902087905551600080516020613fff8339815191529061170a90879087908790613b8c565b60405180910390a2505050505050565b33611723611f3b565b6001600160a01b0316146117495760405162461bcd60e51b815260040161048590613e25565b61271081111561176b5760405162461bcd60e51b815260040161048590613933565b6001600160a01b03909116600090815260ca6020526040902055565b33611790611f3b565b6001600160a01b0316146117b65760405162461bcd60e51b815260040161048590613e25565b815183511480156117c8575080518251145b6117e45760405162461bcd60e51b815260040161048590613d46565b6117ed83611b0f565b6001600160a01b038416600090815260c960205260408120541561182c576001600160a01b038516600090815260c96020526040812061182c91612e4c565b60005b84518110156119eb5760006001600160a01b0316838281518110611855576118556138be565b60200260200101516001600160a01b0316036118835760405162461bcd60e51b815260040161048590613d8c565b60c96000876001600160a01b03166001600160a01b0316815260200190815260200160002060405180604001604052808784815181106118c5576118c56138be565b602002602001015181526020018684815181106118e4576118e46138be565b602090810291909101810151909152825460018101845560009384529220815191926002020190819061191790826139e8565b50602082015181600101555050828181518110611936576119366138be565b602002602001015160cb6000886001600160a01b03166001600160a01b03168152602001908152602001600020868381518110611975576119756138be565b602002602001015160405161198a9190613aa7565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508381815181106119ce576119ce6138be565b6020026020010151826119e19190613dcd565b915060010161182f565b508061271014611a0d5760405162461bcd60e51b815260040161048590613de0565b846001600160a01b0316600080516020613fff833981519152858585604051611a3893929190613b8c565b60405180910390a25050505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611a8f5760405162461bcd60e51b815260040161048590613e5a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611ac16129a3565b6001600160a01b031614611ae75760405162461bcd60e51b815260040161048590613e94565b611af0816129bf565b60408051600080825260208201909252611b0c918391906129ee565b50565b60005b8151811015611c04576000611b28826001613dcd565b90505b8251811015611bfb57828181518110611b4657611b466138be565b6020026020010151604051602001611b5e9190613aa7565b60405160208183030381529060405280519060200120838381518110611b8657611b866138be565b6020026020010151604051602001611b9e9190613aa7565b6040516020818303038152906040528051906020012003611bf35760405162461bcd60e51b815260206004820152600f60248201526e29b0b6b29024b232b73a34b334b2b960891b6044820152606401610485565b600101611b2b565b50600101611b12565b5050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611c505760405162461bcd60e51b815260040161048590613e5a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611c826129a3565b6001600160a01b031614611ca85760405162461bcd60e51b815260040161048590613e94565b611cb1826129bf565b611c04828260016129ee565b81158015611cc9575080155b15611e1557604051631df601a560e11b81526001600160a01b03851690633bec034a90611cfa908690600401613bf4565b602060405180830381865afa158015611d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3b91906138d4565b604051635bd5a2db60e11b81529092506001600160a01b0385169063b7ab45b690611d6a908690600401613bf4565b602060405180830381865afa158015611d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dab91906138d4565b6040516347626d7b60e11b81529091506001600160a01b03851690638ec4daf690611dde90869086908690600401613bcf565b600060405180830381600087803b158015611df857600080fd5b505af1158015611e0c573d6000803e3d6000fd5b50505050611e78565b6040516347626d7b60e11b81526001600160a01b03851690638ec4daf690611e4590869086908690600401613bcf565b600060405180830381600087803b158015611e5f57600080fd5b505af1158015611e73573d6000803e3d6000fd5b505050505b6001600160a01b038416600090815260cb6020526040908190209051611e9f908590613aa7565b908152604051908190036020018120546001600160a01b03908116919086169033907f7fae7c2b80d1f6ec9483f93926c750ae41ef8c4c12165b124309eac333a452e990611ef290889088908890613bcf565b60405180910390a450505050565b33611f09611f3b565b6001600160a01b031614611f2f5760405162461bcd60e51b815260040161048590613e25565b611f396000612b35565b565b6033546001600160a01b031690565b60c96020528160005260406000208181548110611f6657600080fd5b906000526020600020906002020160009150915050806000018054611f8a9061395f565b80601f0160208091040260200160405190810160405280929190818152602001828054611fb69061395f565b80156120035780601f10611fd857610100808354040283529160200191612003565b820191906000526020600020905b815481529060010190602001808311611fe657829003601f168201915b5050505050908060010154905082565b6001600160a01b038116600090815260c960209081526040808320805482518185028101850190935280835260609492939192909184015b82821015612119578382906000526020600020906002020160405180604001604052908160008201805461207e9061395f565b80601f01602080910402602001604051908101604052809291908181526020018280546120aa9061395f565b80156120f75780601f106120cc576101008083540402835291602001916120f7565b820191906000526020600020905b8154815290600101906020018083116120da57829003601f168201915b505050505081526020016001820154815250508152602001906001019061204b565b505050509050919050565b3361212d611f3b565b6001600160a01b0316146121535760405162461bcd60e51b815260040161048590613e25565b6001600160a01b0381166121b75760405162461bcd60e51b815260206004820152602560248201527f4e6577207769746864726177657220616464726573732063616e6e6f74206265604482015264207a65726f60d81b6064820152608401610485565b6001600160a01b038316600090815260cb60205260409081902090518291906121e1908590613aa7565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b0319909216919091179055505050565b600054610100900460ff166122305760005460ff1615612234565b303b155b6122975760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610485565b600054610100900460ff161580156122b9576000805461ffff19166101011790555b6122c1612b87565b6122c9612bbe565b60cc80546001600160a01b0319166001600160a01b0384161790558015611c04576000805461ff00191690555050565b8151815184516000816001600160401b0381111561231957612319612edb565b604051908082528060200260200182016040528015612342578160200160208202803683370190505b50905060008411806123545750600083115b15612592578284146123a25760405162461bcd60e51b8152602060048201526017602482015276416d6f756e7473206c656e677468206e6f742073616d6560481b6044820152606401610485565b8184146124005760405162461bcd60e51b815260206004820152602660248201527f416d6f756e747320616e64204964656e746966657273206c656e677468206e6f604482015265742073616d6560d01b6064820152608401610485565b60005b82811015612555576001600160a01b038916600090815260cb602052604090208851899083908110612437576124376138be565b602002602001015160405161244c9190613aa7565b9081526040519081900360200190205482516001600160a01b039091169083908390811061247c5761247c6138be565b60200260200101906001600160a01b031690816001600160a01b031681525050886001600160a01b0316638ec4daf68983815181106124bd576124bd6138be565b60200260200101518984815181106124d7576124d76138be565b60200260200101518985815181106124f1576124f16138be565b60200260200101516040518463ffffffff1660e01b815260040161251793929190613bcf565b600060405180830381600087803b15801561253157600080fd5b505af1158015612545573d6000803e3d6000fd5b5050600190920191506124039050565b50336001600160a01b0316600080516020613f788339815191528989848a8a604051612585959493929190613ece565b60405180910390a26128f6565b6000826001600160401b038111156125ac576125ac612edb565b6040519080825280602002602001820160405280156125d5578160200160208202803683370190505b5090506000836001600160401b038111156125f2576125f2612edb565b60405190808252806020026020018201604052801561261b578160200160208202803683370190505b50905060005b848110156128bb576001600160a01b038b16600090815260cb602052604090208a518b9083908110612655576126556138be565b602002602001015160405161266a9190613aa7565b9081526040519081900360200190205484516001600160a01b039091169085908390811061269a5761269a6138be565b60200260200101906001600160a01b031690816001600160a01b0316815250508a6001600160a01b0316633bec034a8b83815181106126db576126db6138be565b60200260200101516040518263ffffffff1660e01b81526004016126ff9190613bf4565b602060405180830381865afa15801561271c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274091906138d4565b838281518110612752576127526138be565b6020026020010181815250508a6001600160a01b031663b7ab45b68b838151811061277f5761277f6138be565b60200260200101516040518263ffffffff1660e01b81526004016127a39190613bf4565b602060405180830381865afa1580156127c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e491906138d4565b8282815181106127f6576127f66138be565b6020026020010181815250508a6001600160a01b0316638ec4daf68b8381518110612823576128236138be565b602002602001015185848151811061283d5761283d6138be565b6020026020010151858581518110612857576128576138be565b60200260200101516040518463ffffffff1660e01b815260040161287d93929190613bcf565b600060405180830381600087803b15801561289757600080fd5b505af11580156128ab573d6000803e3d6000fd5b5050600190920191506126219050565b50336001600160a01b0316600080516020613f788339815191528b8b8686866040516128eb959493929190613ece565b60405180910390a250505b5050505050505050565b33612909611f3b565b6001600160a01b03161461292f5760405162461bcd60e51b815260040161048590613e25565b6001600160a01b0381166129945760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610485565b611b0c81612b35565b3b151590565b600080516020613fb8833981519152546001600160a01b031690565b336129c8611f3b565b6001600160a01b031614611b0c5760405162461bcd60e51b815260040161048590613e25565b60006129f86129a3565b9050612a0384612bf5565b600083511180612a105750815b15612a2157612a1f8484612c88565b505b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143805460ff16612b2e57805460ff19166001178155604051612a9c908690612a6d908590602401613562565b60408051601f198184030181529190526020810180516001600160e01b0316631b2ce7f360e11b179052612c88565b50805460ff19168155612aad6129a3565b6001600160a01b0316826001600160a01b031614612b255760405162461bcd60e51b815260206004820152602f60248201527f45524331393637557067726164653a207570677261646520627265616b73206660448201526e75727468657220757067726164657360881b6064820152608401610485565b612b2e85612d75565b5050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff16612bae5760405162461bcd60e51b815260040161048590613f2c565b612bb6612db5565b611f39612db5565b600054610100900460ff16612be55760405162461bcd60e51b815260040161048590613f2c565b612bed612db5565b611f39612ddc565b803b612c595760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610485565b600080516020613fb883398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060823b612ce75760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610485565b600080846001600160a01b031684604051612d029190613aa7565b600060405180830381855af49150503d8060008114612d3d576040519150601f19603f3d011682016040523d82523d6000602084013e612d42565b606091505b5091509150612d6a8282604051806060016040528060278152602001613fd860279139612e0c565b925050505b92915050565b612d7e81612bf5565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b600054610100900460ff16611f395760405162461bcd60e51b815260040161048590613f2c565b600054610100900460ff16612e035760405162461bcd60e51b815260040161048590613f2c565b611f3933612b35565b60608315612e1b575081612e45565b825115612e2b5782518084602001fd5b8160405162461bcd60e51b81526004016104859190613bf4565b9392505050565b5080546000825560020290600052602060002090810190611b0c91905b80821115612e8d576000612e7d8282612e91565b5060006001820155600201612e69565b5090565b508054612e9d9061395f565b6000825580601f10612ead575050565b601f016020900490600052602060002090810190611b0c91905b80821115612e8d5760008155600101612ec7565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b0381118282101715612f1357612f13612edb565b60405290565b604051601f8201601f191681016001600160401b0381118282101715612f4157612f41612edb565b604052919050565b60006001600160401b03821115612f6257612f62612edb565b5060051b60200190565b6001600160a01b0381168114611b0c57600080fd5b600082601f830112612f9257600080fd5b81356020612fa7612fa283612f49565b612f19565b82815260059290921b84018101918181019086841115612fc657600080fd5b8286015b84811015612fea578035612fdd81612f6c565b8352918301918301612fca565b509695505050505050565b60006001600160401b0382111561300e5761300e612edb565b50601f01601f191660200190565b600061302a612fa284612ff5565b905082815283838301111561303e57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261306657600080fd5b612e458383356020850161301c565b600082601f83011261308657600080fd5b81356020613096612fa283612f49565b82815260059290921b840181019181810190868411156130b557600080fd5b8286015b84811015612fea5780356001600160401b038111156130d85760008081fd5b6130e68986838b0101613055565b8452509183019183016130b9565b600082601f83011261310557600080fd5b81356020613115612fa283612f49565b82815260059290921b8401810191818101908684111561313457600080fd5b8286015b84811015612fea5780358352918301918301613138565b600082601f83011261316057600080fd5b81356020613170612fa283612f49565b82815260059290921b8401810191818101908684111561318f57600080fd5b8286015b84811015612fea5780356001600160401b038111156131b25760008081fd5b6131c08986838b01016130f4565b845250918301918301613193565b600080600080608085870312156131e457600080fd5b84356001600160401b03808211156131fb57600080fd5b61320788838901612f81565b955060209150818701358181111561321e57600080fd5b8701601f8101891361322f57600080fd5b803561323d612fa282612f49565b81815260059190911b8201840190848101908b83111561325c57600080fd5b8584015b83811015613294578035868111156132785760008081fd5b6132868e8983890101613075565b845250918601918601613260565b50975050505060408701359150808211156132ae57600080fd5b6132ba8883890161314f565b935060608701359150808211156132d057600080fd5b506132dd8782880161314f565b91505092959194509250565b600080600080600060a0868803121561330157600080fd5b853561330c81612f6c565b94506020860135935060408601356001600160401b038082111561332f57600080fd5b61333b89838a01613075565b9450606088013591508082111561335157600080fd5b61335d89838a016130f4565b9350608088013591508082111561337357600080fd5b5061338088828901612f81565b9150509295509295909350565b600080604083850312156133a057600080fd5b82356133ab81612f6c565b946020939093013593505050565b600080600080608085870312156133cf57600080fd5b84356133da81612f6c565b935060208501356001600160401b03808211156133f657600080fd5b61340288838901613075565b9450604087013591508082111561341857600080fd5b613424888389016130f4565b9350606087013591508082111561343a57600080fd5b506132dd87828801612f81565b60006020828403121561345957600080fd5b8135612e4581612f6c565b60006020828403121561347657600080fd5b81356001600160401b0381111561348c57600080fd5b61349884828501613075565b949350505050565b600080604083850312156134b357600080fd5b82356134be81612f6c565b915060208301356001600160401b038111156134d957600080fd5b8301601f810185136134ea57600080fd5b6134f98582356020840161301c565b9150509250929050565b6000806000806080858703121561351957600080fd5b843561352481612f6c565b935060208501356001600160401b0381111561353f57600080fd5b61354b87828801613055565b949794965050505060408301359260600135919050565b6001600160a01b0391909116815260200190565b60005b83811015613591578181015183820152602001613579565b50506000910152565b600081518084526135b2816020860160208601613576565b601f01601f19169290920160200192915050565b6040815260006135d9604083018561359a565b90508260208301529392505050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561365057888303603f19018552815180518785526136338886018261359a565b91890151948901949094529487019492509086019060010161360f565b509098975050505050505050565b60008060006060848603121561367357600080fd5b833561367e81612f6c565b925060208401356001600160401b0381111561369957600080fd5b6136a586828701613055565b92505060408401356136b681612f6c565b809150509250925092565b600080600080608085870312156136d757600080fd5b84356136e281612f6c565b935060208501356001600160401b03808211156136fe57600080fd5b61370a88838901613075565b9450604087013591508082111561372057600080fd5b61372c888389016130f4565b9350606087013591508082111561374257600080fd5b506132dd878288016130f4565b6000806040838503121561376257600080fd5b823561376d81612f6c565b915060208301356001600160401b0381111561378857600080fd5b6134f985828601613055565b8051600581106137a357600080fd5b919050565b600082601f8301126137b957600080fd5b81516137c7612fa282612ff5565b8181528460208386010111156137dc57600080fd5b613498826020830160208701613576565b80516137a381612f6c565b60006020828403121561380a57600080fd5b81516001600160401b038082111561382157600080fd5b9083019060c0828603121561383557600080fd5b61383d612ef1565b61384683613794565b8152602083015160208201526040830151604082015260608301518281111561386e57600080fd5b61387a878286016137a8565b60608301525061388c608084016137ed565b608082015260a0830151828111156138a357600080fd5b6138af878286016137a8565b60a08301525095945050505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156138e657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115612d6f57612d6f6138ed565b60006020828403121561392857600080fd5b8151612e4581612f6c565b6020808252601290820152710546f74616c20666565203c3d2031303030360741b604082015260600190565b600181811c9082168061397357607f821691505b60208210810361399357634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156139e357600081815260208120601f850160051c810160208610156139c05750805b601f850160051c820191505b818110156139df578281556001016139cc565b5050505b505050565b81516001600160401b03811115613a0157613a01612edb565b613a1581613a0f845461395f565b84613999565b602080601f831160018114613a4a5760008415613a325750858301515b600019600386901b1c1916600185901b1785556139df565b600085815260208120601f198616915b82811015613a7957888601518255948401946001909101908401613a5a565b5085821015613a975787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251613ab9818460208701613576565b9190910192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015613b0b578284038952613af984835161359a565b98850198935090840190600101613ae1565b5091979650505050505050565b600081518084526020808501945080840160005b83811015613b4857815187529582019590820190600101613b2c565b509495945050505050565b600081518084526020808501945080840160005b83811015613b485781516001600160a01b031687529582019590820190600101613b67565b606081526000613b9f6060830186613ac3565b8281036020840152613bb18186613b18565b90508281036040840152613bc58185613b53565b9695505050505050565b606081526000613be2606083018661359a565b60208301949094525060400152919050565b602081526000612e45602083018461359a565b600081518084526020808501808196508360051b8101915082860160005b85811015613b0b578284038952613c3d848351613b53565b98850198935090840190600101613c25565b600081518084526020808501808196508360051b8101915082860160005b85811015613b0b578284038952613c85848351613b18565b98850198935090840190600101613c6d565b60a081526000613caa60a0830188613b53565b6020838203818501528188518084528284019150828160051b850101838b0160005b83811015613cfa57601f19878403018552613ce8838351613ac3565b94860194925090850190600101613ccc565b50508681036040880152613d0e818b613c07565b9450505050508281036060840152613d268186613c4f565b90508281036080840152613d3a8185613c4f565b98975050505050505050565b60208082526026908201527f496e70757420617272617973206d7573742068617665207468652073616d65206040820152650d8cadccee8d60d31b606082015260800190565b60208082526021908201527f5769746864726177657220616464726573732063616e6e6f74206265207a65726040820152606f60f81b606082015260800190565b80820180821115612d6f57612d6f6138ed565b60208082526025908201527f546f74616c206665652076616c7565206d7573742062652065786163746c7920604082015264031303030360dc1b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602c90820152600080516020613f9883398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c90820152600080516020613f9883398151915260408201526b6163746976652070726f787960a01b606082015260800190565b6001600160a01b038616815260a060208201819052600090613ef290830187613ac3565b8281036040840152613f048187613b53565b90508281036060840152613f188186613b18565b90508281036080840152613d3a8185613b18565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fe2f3b4d60c70afc6d9a8efad062f024bdb01e0745e30cf9bc8361667a1f21b2bd46756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656437ffe35f585b70b4482e8727f8e1e3f23e6f0d331ec1137578cfdff8e52187f6a2646970667358221220a2e69f265261700e9e3bae92440bfd2727f063556248788dca6486cf0b48ed5c64736f6c63430008120033

Deployed ByteCode

0x6080604052600436106100ef5760003560e01c806304e493fd146100f4578063130a19821461010b57806316828da81461012b578063249518e91461014b57806325d8456d1461016b5780633659cfe61461018b578063387024ac146101ab5780634f1ef286146101cb5780635376c803146101de578063715018a6146101fe5780638da5cb5b1461021357806390cfc4061461023e578063912cb891146102795780639af608c9146102a7578063bcc27dd9146102d4578063c4d66de8146102f4578063cdd7b38a14610314578063dece884d14610334578063f2fde38b14610354578063f3aefd5514610374575b600080fd5b34801561010057600080fd5b506101096103c6565b005b34801561011757600080fd5b506101096101263660046131ce565b610aae565b34801561013757600080fd5b506101096101463660046132e9565b611447565b34801561015757600080fd5b5061010961016636600461338d565b61171a565b34801561017757600080fd5b506101096101863660046133b9565b611787565b34801561019757600080fd5b506101096101a6366004613447565b611a47565b3480156101b757600080fd5b506101096101c6366004613464565b611b0f565b6101096101d93660046134a0565b611c08565b3480156101ea57600080fd5b506101096101f9366004613503565b611cbd565b34801561020a57600080fd5b50610109611f00565b34801561021f57600080fd5b50610228611f3b565b6040516102359190613562565b60405180910390f35b34801561024a57600080fd5b5061026b610259366004613447565b60ca6020526000908152604090205481565b604051908152602001610235565b34801561028557600080fd5b5061029961029436600461338d565b611f4a565b6040516102359291906135c6565b3480156102b357600080fd5b506102c76102c2366004613447565b612013565b60405161023591906135e8565b3480156102e057600080fd5b506101096102ef36600461365e565b612124565b34801561030057600080fd5b5061010961030f366004613447565b612215565b34801561032057600080fd5b5060cc54610228906001600160a01b031681565b34801561034057600080fd5b5061010961034f3660046136c1565b6122f9565b34801561036057600080fd5b5061010961036f366004613447565b612900565b34801561038057600080fd5b5061022861038f36600461374f565b60cb60209081526000928352604090922081518083018401805192815290840192909301919091209152546001600160a01b031681565b60cc546040516367a44ca360e01b815233916001600160a01b0316906367a44ca3906103f6908490600401613562565b600060405180830381865afa158015610413573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261043b91908101906137f8565b608001516001600160a01b03161461048e5760405162461bcd60e51b8152602060048201526011602482015270139bdd08104814dd19595c8815985d5b1d607a1b60448201526064015b60405180910390fd5b60408051600280825260608201909252600091816020015b60608152602001906001900390816104a65790505090506040518060400160405280600a81526020016953544545525f4645455360b01b815250816000815181106104f3576104f36138be565b60200260200101819052506040518060400160405280600f81526020016e535452415445474953545f4645455360881b81525081600181518110610539576105396138be565b602090810291909101015260408051600280825260608201909252600091816020016020820280368337019050509050336001600160a01b0316631c1f19366040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cb91906138d4565b816000815181106105de576105de6138be565b602002602001018181525050806000815181106105fd576105fd6138be565b60200260200101516127106106129190613903565b81600181518110610625576106256138be565b602090810291909101015260408051600280825260608201909252600091816020016020820280368337505060cc5460408051638da5cb5b60e01b815290519394506001600160a01b0390911692638da5cb5b925060048083019260209291908290030181865afa15801561069e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c29190613916565b816000815181106106d5576106d56138be565b6001600160a01b03928316602091820292909201015260cc5460405163015a1d6760e31b8152911690630ad0eb3890610712903390600401613562565b602060405180830381865afa15801561072f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107539190613916565b81600181518110610766576107666138be565b60200260200101906001600160a01b031690816001600160a01b0316815250506000336001600160a01b03166363db7eae6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ea91906138d4565b905061271081111561080e5760405162461bcd60e51b815260040161048590613933565b33600090815260c96020526040808220815180830190925286519092829188919061083b5761083b6138be565b602002602001015181526020018560008151811061085b5761085b6138be565b602090810291909101810151909152825460018101845560009384529220815191926002020190819061088e90826139e8565b5060208201518160010155505060c96000336001600160a01b03166001600160a01b031681526020019081526020016000206040518060400160405280866001815181106108de576108de6138be565b60200260200101518152602001856001815181106108fe576108fe6138be565b602090810291909101810151909152825460018101845560009384529220815191926002020190819061093190826139e8565b5060208201518160010155505081600081518110610951576109516138be565b602002602001015160cb6000336001600160a01b03166001600160a01b0316815260200190815260200160002085600081518110610991576109916138be565b60200260200101516040516109a69190613aa7565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001815181106109eb576109eb6138be565b602002602001015160cb6000336001600160a01b03166001600160a01b0316815260200190815260200160002085600181518110610a2b57610a2b6138be565b6020026020010151604051610a409190613aa7565b908152604080516020928190038301812080546001600160a01b0319166001600160a01b03959095169490941790935533600081815260ca909352912083905590600080516020613fff83398151915290610aa090879087908790613b8c565b60405180910390a250505050565b82518451148015610ac0575081518451145b8015610acd575080518451145b610b145760405162461bcd60e51b8152602060048201526018602482015277082e4e4c2f240d8cadccee8d0e640daeae6e840dac2e8c6d60431b6044820152606401610485565b600084516001600160401b03811115610b2f57610b2f612edb565b604051908082528060200260200182016040528015610b6257816020015b6060815260200190600190039081610b4d5790505b509050600085516001600160401b03811115610b8057610b80612edb565b604051908082528060200260200182016040528015610bb357816020015b6060815260200190600190039081610b9e5790505b509050600086516001600160401b03811115610bd157610bd1612edb565b604051908082528060200260200182016040528015610c0457816020015b6060815260200190600190039081610bef5790505b50905060005b87518110156113f4576000888281518110610c2757610c276138be565b602002602001015190506000888381518110610c4557610c456138be565b60200260200101519050600081519050806001600160401b03811115610c6d57610c6d612edb565b604051908082528060200260200182016040528015610c96578160200160208202803683370190505b50878581518110610ca957610ca96138be565b6020026020010181905250806001600160401b03811115610ccc57610ccc612edb565b604051908082528060200260200182016040528015610cf5578160200160208202803683370190505b50868581518110610d0857610d086138be565b6020026020010181905250806001600160401b03811115610d2b57610d2b612edb565b604051908082528060200260200182016040528015610d54578160200160208202803683370190505b50858581518110610d6757610d676138be565b60200260200101819052506000898581518110610d8657610d866138be565b6020026020010151511180610db557506000888581518110610daa57610daa6138be565b602002602001015151115b156110cd5780898581518110610dcd57610dcd6138be565b602002602001015151148015610dfc575080888581518110610df157610df16138be565b602002602001015151145b610e585760405162461bcd60e51b815260206004820152602760248201527f416d6f756e747320616e64204964656e74696669657273206c656e677468206d6044820152660d2e6dac2e8c6d60cb1b6064820152608401610485565b60005b818110156110c7576001600160a01b038416600090815260cb602052604090208351849083908110610e8f57610e8f6138be565b6020026020010151604051610ea49190613aa7565b9081526040519081900360200190205488516001600160a01b0390911690899087908110610ed457610ed46138be565b60200260200101518281518110610eed57610eed6138be565b60200260200101906001600160a01b031690816001600160a01b031681525050836001600160a01b0316638ec4daf6848381518110610f2e57610f2e6138be565b60200260200101518c8881518110610f4857610f486138be565b60200260200101518481518110610f6157610f616138be565b60200260200101518c8981518110610f7b57610f7b6138be565b60200260200101518581518110610f9457610f946138be565b60200260200101516040518463ffffffff1660e01b8152600401610fba93929190613bcf565b600060405180830381600087803b158015610fd457600080fd5b505af1158015610fe8573d6000803e3d6000fd5b50505050898581518110610ffe57610ffe6138be565b60200260200101518181518110611017576110176138be565b6020026020010151878681518110611031576110316138be565b6020026020010151828151811061104a5761104a6138be565b602002602001018181525050888581518110611068576110686138be565b60200260200101518181518110611081576110816138be565b602002602001015186868151811061109b5761109b6138be565b602002602001015182815181106110b4576110b46138be565b6020908102919091010152600101610e5b565b506113e9565b60005b818110156113e7576001600160a01b038416600090815260cb602052604090208351849083908110611104576111046138be565b60200260200101516040516111199190613aa7565b9081526040519081900360200190205488516001600160a01b0390911690899087908110611149576111496138be565b60200260200101518281518110611162576111626138be565b60200260200101906001600160a01b031690816001600160a01b031681525050836001600160a01b0316633bec034a8483815181106111a3576111a36138be565b60200260200101516040518263ffffffff1660e01b81526004016111c79190613bf4565b602060405180830381865afa1580156111e4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120891906138d4565b87868151811061121a5761121a6138be565b60200260200101518281518110611233576112336138be565b602002602001018181525050836001600160a01b031663b7ab45b6848381518110611260576112606138be565b60200260200101516040518263ffffffff1660e01b81526004016112849190613bf4565b602060405180830381865afa1580156112a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c591906138d4565b8686815181106112d7576112d76138be565b602002602001015182815181106112f0576112f06138be565b602002602001018181525050836001600160a01b0316638ec4daf684838151811061131d5761131d6138be565b6020026020010151898881518110611337576113376138be565b60200260200101518481518110611350576113506138be565b602002602001015189898151811061136a5761136a6138be565b60200260200101518581518110611383576113836138be565b60200260200101516040518463ffffffff1660e01b81526004016113a993929190613bcf565b600060405180830381600087803b1580156113c357600080fd5b505af11580156113d7573d6000803e3d6000fd5b5050600190920191506110d09050565b505b505050600101610c0a565b50336001600160a01b03167fee94e1b4e723a9d0391bc453bb49192fdb33320cbd8377328572e9d0966dc7a58888868686604051611436959493929190613c97565b60405180910390a250505050505050565b60cc546001600160a01b031633146114925760405162461bcd60e51b815260206004820152600e60248201526d215661756c74526567697374727960901b6044820152606401610485565b815183511480156114a4575080518251145b6114c05760405162461bcd60e51b815260040161048590613d46565b6114c983611b0f565b6127108411156114eb5760405162461bcd60e51b815260040161048590613933565b6000805b84518110156116ab5760006001600160a01b0316838281518110611515576115156138be565b60200260200101516001600160a01b0316036115435760405162461bcd60e51b815260040161048590613d8c565b60c96000886001600160a01b03166001600160a01b031681526020019081526020016000206040518060400160405280878481518110611585576115856138be565b602002602001015181526020018684815181106115a4576115a46138be565b60209081029190910181015190915282546001810184556000938452922081519192600202019081906115d790826139e8565b506020820151816001015550508281815181106115f6576115f66138be565b602002602001015160cb6000896001600160a01b03166001600160a01b03168152602001908152602001600020868381518110611635576116356138be565b602002602001015160405161164a9190613aa7565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555083818151811061168e5761168e6138be565b6020026020010151826116a19190613dcd565b91506001016114ef565b5080612710146116cd5760405162461bcd60e51b815260040161048590613de0565b6001600160a01b038616600081815260ca60205260409081902087905551600080516020613fff8339815191529061170a90879087908790613b8c565b60405180910390a2505050505050565b33611723611f3b565b6001600160a01b0316146117495760405162461bcd60e51b815260040161048590613e25565b61271081111561176b5760405162461bcd60e51b815260040161048590613933565b6001600160a01b03909116600090815260ca6020526040902055565b33611790611f3b565b6001600160a01b0316146117b65760405162461bcd60e51b815260040161048590613e25565b815183511480156117c8575080518251145b6117e45760405162461bcd60e51b815260040161048590613d46565b6117ed83611b0f565b6001600160a01b038416600090815260c960205260408120541561182c576001600160a01b038516600090815260c96020526040812061182c91612e4c565b60005b84518110156119eb5760006001600160a01b0316838281518110611855576118556138be565b60200260200101516001600160a01b0316036118835760405162461bcd60e51b815260040161048590613d8c565b60c96000876001600160a01b03166001600160a01b0316815260200190815260200160002060405180604001604052808784815181106118c5576118c56138be565b602002602001015181526020018684815181106118e4576118e46138be565b602090810291909101810151909152825460018101845560009384529220815191926002020190819061191790826139e8565b50602082015181600101555050828181518110611936576119366138be565b602002602001015160cb6000886001600160a01b03166001600160a01b03168152602001908152602001600020868381518110611975576119756138be565b602002602001015160405161198a9190613aa7565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508381815181106119ce576119ce6138be565b6020026020010151826119e19190613dcd565b915060010161182f565b508061271014611a0d5760405162461bcd60e51b815260040161048590613de0565b846001600160a01b0316600080516020613fff833981519152858585604051611a3893929190613b8c565b60405180910390a25050505050565b6001600160a01b037f00000000000000000000000031e4ee367d4f2685bafcab9566e9c87e60d48983163003611a8f5760405162461bcd60e51b815260040161048590613e5a565b7f00000000000000000000000031e4ee367d4f2685bafcab9566e9c87e60d489836001600160a01b0316611ac16129a3565b6001600160a01b031614611ae75760405162461bcd60e51b815260040161048590613e94565b611af0816129bf565b60408051600080825260208201909252611b0c918391906129ee565b50565b60005b8151811015611c04576000611b28826001613dcd565b90505b8251811015611bfb57828181518110611b4657611b466138be565b6020026020010151604051602001611b5e9190613aa7565b60405160208183030381529060405280519060200120838381518110611b8657611b866138be565b6020026020010151604051602001611b9e9190613aa7565b6040516020818303038152906040528051906020012003611bf35760405162461bcd60e51b815260206004820152600f60248201526e29b0b6b29024b232b73a34b334b2b960891b6044820152606401610485565b600101611b2b565b50600101611b12565b5050565b6001600160a01b037f00000000000000000000000031e4ee367d4f2685bafcab9566e9c87e60d48983163003611c505760405162461bcd60e51b815260040161048590613e5a565b7f00000000000000000000000031e4ee367d4f2685bafcab9566e9c87e60d489836001600160a01b0316611c826129a3565b6001600160a01b031614611ca85760405162461bcd60e51b815260040161048590613e94565b611cb1826129bf565b611c04828260016129ee565b81158015611cc9575080155b15611e1557604051631df601a560e11b81526001600160a01b03851690633bec034a90611cfa908690600401613bf4565b602060405180830381865afa158015611d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3b91906138d4565b604051635bd5a2db60e11b81529092506001600160a01b0385169063b7ab45b690611d6a908690600401613bf4565b602060405180830381865afa158015611d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dab91906138d4565b6040516347626d7b60e11b81529091506001600160a01b03851690638ec4daf690611dde90869086908690600401613bcf565b600060405180830381600087803b158015611df857600080fd5b505af1158015611e0c573d6000803e3d6000fd5b50505050611e78565b6040516347626d7b60e11b81526001600160a01b03851690638ec4daf690611e4590869086908690600401613bcf565b600060405180830381600087803b158015611e5f57600080fd5b505af1158015611e73573d6000803e3d6000fd5b505050505b6001600160a01b038416600090815260cb6020526040908190209051611e9f908590613aa7565b908152604051908190036020018120546001600160a01b03908116919086169033907f7fae7c2b80d1f6ec9483f93926c750ae41ef8c4c12165b124309eac333a452e990611ef290889088908890613bcf565b60405180910390a450505050565b33611f09611f3b565b6001600160a01b031614611f2f5760405162461bcd60e51b815260040161048590613e25565b611f396000612b35565b565b6033546001600160a01b031690565b60c96020528160005260406000208181548110611f6657600080fd5b906000526020600020906002020160009150915050806000018054611f8a9061395f565b80601f0160208091040260200160405190810160405280929190818152602001828054611fb69061395f565b80156120035780601f10611fd857610100808354040283529160200191612003565b820191906000526020600020905b815481529060010190602001808311611fe657829003601f168201915b5050505050908060010154905082565b6001600160a01b038116600090815260c960209081526040808320805482518185028101850190935280835260609492939192909184015b82821015612119578382906000526020600020906002020160405180604001604052908160008201805461207e9061395f565b80601f01602080910402602001604051908101604052809291908181526020018280546120aa9061395f565b80156120f75780601f106120cc576101008083540402835291602001916120f7565b820191906000526020600020905b8154815290600101906020018083116120da57829003601f168201915b505050505081526020016001820154815250508152602001906001019061204b565b505050509050919050565b3361212d611f3b565b6001600160a01b0316146121535760405162461bcd60e51b815260040161048590613e25565b6001600160a01b0381166121b75760405162461bcd60e51b815260206004820152602560248201527f4e6577207769746864726177657220616464726573732063616e6e6f74206265604482015264207a65726f60d81b6064820152608401610485565b6001600160a01b038316600090815260cb60205260409081902090518291906121e1908590613aa7565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b0319909216919091179055505050565b600054610100900460ff166122305760005460ff1615612234565b303b155b6122975760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610485565b600054610100900460ff161580156122b9576000805461ffff19166101011790555b6122c1612b87565b6122c9612bbe565b60cc80546001600160a01b0319166001600160a01b0384161790558015611c04576000805461ff00191690555050565b8151815184516000816001600160401b0381111561231957612319612edb565b604051908082528060200260200182016040528015612342578160200160208202803683370190505b50905060008411806123545750600083115b15612592578284146123a25760405162461bcd60e51b8152602060048201526017602482015276416d6f756e7473206c656e677468206e6f742073616d6560481b6044820152606401610485565b8184146124005760405162461bcd60e51b815260206004820152602660248201527f416d6f756e747320616e64204964656e746966657273206c656e677468206e6f604482015265742073616d6560d01b6064820152608401610485565b60005b82811015612555576001600160a01b038916600090815260cb602052604090208851899083908110612437576124376138be565b602002602001015160405161244c9190613aa7565b9081526040519081900360200190205482516001600160a01b039091169083908390811061247c5761247c6138be565b60200260200101906001600160a01b031690816001600160a01b031681525050886001600160a01b0316638ec4daf68983815181106124bd576124bd6138be565b60200260200101518984815181106124d7576124d76138be565b60200260200101518985815181106124f1576124f16138be565b60200260200101516040518463ffffffff1660e01b815260040161251793929190613bcf565b600060405180830381600087803b15801561253157600080fd5b505af1158015612545573d6000803e3d6000fd5b5050600190920191506124039050565b50336001600160a01b0316600080516020613f788339815191528989848a8a604051612585959493929190613ece565b60405180910390a26128f6565b6000826001600160401b038111156125ac576125ac612edb565b6040519080825280602002602001820160405280156125d5578160200160208202803683370190505b5090506000836001600160401b038111156125f2576125f2612edb565b60405190808252806020026020018201604052801561261b578160200160208202803683370190505b50905060005b848110156128bb576001600160a01b038b16600090815260cb602052604090208a518b9083908110612655576126556138be565b602002602001015160405161266a9190613aa7565b9081526040519081900360200190205484516001600160a01b039091169085908390811061269a5761269a6138be565b60200260200101906001600160a01b031690816001600160a01b0316815250508a6001600160a01b0316633bec034a8b83815181106126db576126db6138be565b60200260200101516040518263ffffffff1660e01b81526004016126ff9190613bf4565b602060405180830381865afa15801561271c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274091906138d4565b838281518110612752576127526138be565b6020026020010181815250508a6001600160a01b031663b7ab45b68b838151811061277f5761277f6138be565b60200260200101516040518263ffffffff1660e01b81526004016127a39190613bf4565b602060405180830381865afa1580156127c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e491906138d4565b8282815181106127f6576127f66138be565b6020026020010181815250508a6001600160a01b0316638ec4daf68b8381518110612823576128236138be565b602002602001015185848151811061283d5761283d6138be565b6020026020010151858581518110612857576128576138be565b60200260200101516040518463ffffffff1660e01b815260040161287d93929190613bcf565b600060405180830381600087803b15801561289757600080fd5b505af11580156128ab573d6000803e3d6000fd5b5050600190920191506126219050565b50336001600160a01b0316600080516020613f788339815191528b8b8686866040516128eb959493929190613ece565b60405180910390a250505b5050505050505050565b33612909611f3b565b6001600160a01b03161461292f5760405162461bcd60e51b815260040161048590613e25565b6001600160a01b0381166129945760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610485565b611b0c81612b35565b3b151590565b600080516020613fb8833981519152546001600160a01b031690565b336129c8611f3b565b6001600160a01b031614611b0c5760405162461bcd60e51b815260040161048590613e25565b60006129f86129a3565b9050612a0384612bf5565b600083511180612a105750815b15612a2157612a1f8484612c88565b505b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143805460ff16612b2e57805460ff19166001178155604051612a9c908690612a6d908590602401613562565b60408051601f198184030181529190526020810180516001600160e01b0316631b2ce7f360e11b179052612c88565b50805460ff19168155612aad6129a3565b6001600160a01b0316826001600160a01b031614612b255760405162461bcd60e51b815260206004820152602f60248201527f45524331393637557067726164653a207570677261646520627265616b73206660448201526e75727468657220757067726164657360881b6064820152608401610485565b612b2e85612d75565b5050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff16612bae5760405162461bcd60e51b815260040161048590613f2c565b612bb6612db5565b611f39612db5565b600054610100900460ff16612be55760405162461bcd60e51b815260040161048590613f2c565b612bed612db5565b611f39612ddc565b803b612c595760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610485565b600080516020613fb883398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060823b612ce75760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610485565b600080846001600160a01b031684604051612d029190613aa7565b600060405180830381855af49150503d8060008114612d3d576040519150601f19603f3d011682016040523d82523d6000602084013e612d42565b606091505b5091509150612d6a8282604051806060016040528060278152602001613fd860279139612e0c565b925050505b92915050565b612d7e81612bf5565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b600054610100900460ff16611f395760405162461bcd60e51b815260040161048590613f2c565b600054610100900460ff16612e035760405162461bcd60e51b815260040161048590613f2c565b611f3933612b35565b60608315612e1b575081612e45565b825115612e2b5782518084602001fd5b8160405162461bcd60e51b81526004016104859190613bf4565b9392505050565b5080546000825560020290600052602060002090810190611b0c91905b80821115612e8d576000612e7d8282612e91565b5060006001820155600201612e69565b5090565b508054612e9d9061395f565b6000825580601f10612ead575050565b601f016020900490600052602060002090810190611b0c91905b80821115612e8d5760008155600101612ec7565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b0381118282101715612f1357612f13612edb565b60405290565b604051601f8201601f191681016001600160401b0381118282101715612f4157612f41612edb565b604052919050565b60006001600160401b03821115612f6257612f62612edb565b5060051b60200190565b6001600160a01b0381168114611b0c57600080fd5b600082601f830112612f9257600080fd5b81356020612fa7612fa283612f49565b612f19565b82815260059290921b84018101918181019086841115612fc657600080fd5b8286015b84811015612fea578035612fdd81612f6c565b8352918301918301612fca565b509695505050505050565b60006001600160401b0382111561300e5761300e612edb565b50601f01601f191660200190565b600061302a612fa284612ff5565b905082815283838301111561303e57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261306657600080fd5b612e458383356020850161301c565b600082601f83011261308657600080fd5b81356020613096612fa283612f49565b82815260059290921b840181019181810190868411156130b557600080fd5b8286015b84811015612fea5780356001600160401b038111156130d85760008081fd5b6130e68986838b0101613055565b8452509183019183016130b9565b600082601f83011261310557600080fd5b81356020613115612fa283612f49565b82815260059290921b8401810191818101908684111561313457600080fd5b8286015b84811015612fea5780358352918301918301613138565b600082601f83011261316057600080fd5b81356020613170612fa283612f49565b82815260059290921b8401810191818101908684111561318f57600080fd5b8286015b84811015612fea5780356001600160401b038111156131b25760008081fd5b6131c08986838b01016130f4565b845250918301918301613193565b600080600080608085870312156131e457600080fd5b84356001600160401b03808211156131fb57600080fd5b61320788838901612f81565b955060209150818701358181111561321e57600080fd5b8701601f8101891361322f57600080fd5b803561323d612fa282612f49565b81815260059190911b8201840190848101908b83111561325c57600080fd5b8584015b83811015613294578035868111156132785760008081fd5b6132868e8983890101613075565b845250918601918601613260565b50975050505060408701359150808211156132ae57600080fd5b6132ba8883890161314f565b935060608701359150808211156132d057600080fd5b506132dd8782880161314f565b91505092959194509250565b600080600080600060a0868803121561330157600080fd5b853561330c81612f6c565b94506020860135935060408601356001600160401b038082111561332f57600080fd5b61333b89838a01613075565b9450606088013591508082111561335157600080fd5b61335d89838a016130f4565b9350608088013591508082111561337357600080fd5b5061338088828901612f81565b9150509295509295909350565b600080604083850312156133a057600080fd5b82356133ab81612f6c565b946020939093013593505050565b600080600080608085870312156133cf57600080fd5b84356133da81612f6c565b935060208501356001600160401b03808211156133f657600080fd5b61340288838901613075565b9450604087013591508082111561341857600080fd5b613424888389016130f4565b9350606087013591508082111561343a57600080fd5b506132dd87828801612f81565b60006020828403121561345957600080fd5b8135612e4581612f6c565b60006020828403121561347657600080fd5b81356001600160401b0381111561348c57600080fd5b61349884828501613075565b949350505050565b600080604083850312156134b357600080fd5b82356134be81612f6c565b915060208301356001600160401b038111156134d957600080fd5b8301601f810185136134ea57600080fd5b6134f98582356020840161301c565b9150509250929050565b6000806000806080858703121561351957600080fd5b843561352481612f6c565b935060208501356001600160401b0381111561353f57600080fd5b61354b87828801613055565b949794965050505060408301359260600135919050565b6001600160a01b0391909116815260200190565b60005b83811015613591578181015183820152602001613579565b50506000910152565b600081518084526135b2816020860160208601613576565b601f01601f19169290920160200192915050565b6040815260006135d9604083018561359a565b90508260208301529392505050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561365057888303603f19018552815180518785526136338886018261359a565b91890151948901949094529487019492509086019060010161360f565b509098975050505050505050565b60008060006060848603121561367357600080fd5b833561367e81612f6c565b925060208401356001600160401b0381111561369957600080fd5b6136a586828701613055565b92505060408401356136b681612f6c565b809150509250925092565b600080600080608085870312156136d757600080fd5b84356136e281612f6c565b935060208501356001600160401b03808211156136fe57600080fd5b61370a88838901613075565b9450604087013591508082111561372057600080fd5b61372c888389016130f4565b9350606087013591508082111561374257600080fd5b506132dd878288016130f4565b6000806040838503121561376257600080fd5b823561376d81612f6c565b915060208301356001600160401b0381111561378857600080fd5b6134f985828601613055565b8051600581106137a357600080fd5b919050565b600082601f8301126137b957600080fd5b81516137c7612fa282612ff5565b8181528460208386010111156137dc57600080fd5b613498826020830160208701613576565b80516137a381612f6c565b60006020828403121561380a57600080fd5b81516001600160401b038082111561382157600080fd5b9083019060c0828603121561383557600080fd5b61383d612ef1565b61384683613794565b8152602083015160208201526040830151604082015260608301518281111561386e57600080fd5b61387a878286016137a8565b60608301525061388c608084016137ed565b608082015260a0830151828111156138a357600080fd5b6138af878286016137a8565b60a08301525095945050505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156138e657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115612d6f57612d6f6138ed565b60006020828403121561392857600080fd5b8151612e4581612f6c565b6020808252601290820152710546f74616c20666565203c3d2031303030360741b604082015260600190565b600181811c9082168061397357607f821691505b60208210810361399357634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156139e357600081815260208120601f850160051c810160208610156139c05750805b601f850160051c820191505b818110156139df578281556001016139cc565b5050505b505050565b81516001600160401b03811115613a0157613a01612edb565b613a1581613a0f845461395f565b84613999565b602080601f831160018114613a4a5760008415613a325750858301515b600019600386901b1c1916600185901b1785556139df565b600085815260208120601f198616915b82811015613a7957888601518255948401946001909101908401613a5a565b5085821015613a975787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251613ab9818460208701613576565b9190910192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015613b0b578284038952613af984835161359a565b98850198935090840190600101613ae1565b5091979650505050505050565b600081518084526020808501945080840160005b83811015613b4857815187529582019590820190600101613b2c565b509495945050505050565b600081518084526020808501945080840160005b83811015613b485781516001600160a01b031687529582019590820190600101613b67565b606081526000613b9f6060830186613ac3565b8281036020840152613bb18186613b18565b90508281036040840152613bc58185613b53565b9695505050505050565b606081526000613be2606083018661359a565b60208301949094525060400152919050565b602081526000612e45602083018461359a565b600081518084526020808501808196508360051b8101915082860160005b85811015613b0b578284038952613c3d848351613b53565b98850198935090840190600101613c25565b600081518084526020808501808196508360051b8101915082860160005b85811015613b0b578284038952613c85848351613b18565b98850198935090840190600101613c6d565b60a081526000613caa60a0830188613b53565b6020838203818501528188518084528284019150828160051b850101838b0160005b83811015613cfa57601f19878403018552613ce8838351613ac3565b94860194925090850190600101613ccc565b50508681036040880152613d0e818b613c07565b9450505050508281036060840152613d268186613c4f565b90508281036080840152613d3a8185613c4f565b98975050505050505050565b60208082526026908201527f496e70757420617272617973206d7573742068617665207468652073616d65206040820152650d8cadccee8d60d31b606082015260800190565b60208082526021908201527f5769746864726177657220616464726573732063616e6e6f74206265207a65726040820152606f60f81b606082015260800190565b80820180821115612d6f57612d6f6138ed565b60208082526025908201527f546f74616c206665652076616c7565206d7573742062652065786163746c7920604082015264031303030360dc1b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602c90820152600080516020613f9883398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c90820152600080516020613f9883398151915260408201526b6163746976652070726f787960a01b606082015260800190565b6001600160a01b038616815260a060208201819052600090613ef290830187613ac3565b8281036040840152613f048187613b53565b90508281036060840152613f188186613b18565b90508281036080840152613d3a8185613b18565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fe2f3b4d60c70afc6d9a8efad062f024bdb01e0745e30cf9bc8361667a1f21b2bd46756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656437ffe35f585b70b4482e8727f8e1e3f23e6f0d331ec1137578cfdff8e52187f6a2646970667358221220a2e69f265261700e9e3bae92440bfd2727f063556248788dca6486cf0b48ed5c64736f6c63430008120033