AVAX Price: $17.70 (+2.42%)
 

Overview

AVAX Balance

Avalanche C-Chain LogoAvalanche C-Chain LogoAvalanche C-Chain Logo0 AVAX

AVAX Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Pending Owne...224270772022-11-15 23:29:181089 days ago1668554958IN
Trader Joe: LBFactory
0 AVAX0.0012569726.5
Set Preset224269582022-11-15 23:25:101089 days ago1668554710IN
Trader Joe: LBFactory
0 AVAX0.0016227628.13194438
Set Preset224269582022-11-15 23:25:101089 days ago1668554710IN
Trader Joe: LBFactory
0 AVAX0.0016227628.13194438
Set Preset224269582022-11-15 23:25:101089 days ago1668554710IN
Trader Joe: LBFactory
0 AVAX0.0016227628.13194438
Set Preset224269582022-11-15 23:25:101089 days ago1668554710IN
Trader Joe: LBFactory
0 AVAX0.001623128.13194438
Set Preset224269582022-11-15 23:25:101089 days ago1668554710IN
Trader Joe: LBFactory
0 AVAX0.0016227628.13194438
Set Preset224269582022-11-15 23:25:101089 days ago1668554710IN
Trader Joe: LBFactory
0 AVAX0.0021038128.13194438
Add Quote Asset224269562022-11-15 23:25:051089 days ago1668554705IN
Trader Joe: LBFactory
0 AVAX0.0025744628
Set LB Pair Impl...224269562022-11-15 23:25:051089 days ago1668554705IN
Trader Joe: LBFactory
0 AVAX0.0014255328

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
278516842023-03-24 15:31:18961 days ago1679671878
Trader Joe: LBFactory
 Contract Creation0 AVAX
278516842023-03-24 15:31:18961 days ago1679671878
Trader Joe: LBFactory
 Contract Creation0 AVAX
275249742023-03-16 19:42:42968 days ago1678995762
Trader Joe: LBFactory
 Contract Creation0 AVAX
274205042023-03-14 8:43:04971 days ago1678783384
Trader Joe: LBFactory
 Contract Creation0 AVAX
272082452023-03-09 9:53:14976 days ago1678355594
Trader Joe: LBFactory
 Contract Creation0 AVAX
272082452023-03-09 9:53:14976 days ago1678355594
Trader Joe: LBFactory
 Contract Creation0 AVAX
266027762023-02-22 20:36:34990 days ago1677098194
Trader Joe: LBFactory
 Contract Creation0 AVAX
262957852023-02-15 16:27:59998 days ago1676478479
Trader Joe: LBFactory
 Contract Creation0 AVAX
254877582023-01-27 16:50:121017 days ago1674838212
Trader Joe: LBFactory
 Contract Creation0 AVAX
254877582023-01-27 16:50:121017 days ago1674838212
Trader Joe: LBFactory
 Contract Creation0 AVAX
251047112023-01-18 15:23:581026 days ago1674055438
Trader Joe: LBFactory
 Contract Creation0 AVAX
248041862023-01-11 14:09:581033 days ago1673446198
Trader Joe: LBFactory
 Contract Creation0 AVAX
248041862023-01-11 14:09:581033 days ago1673446198
Trader Joe: LBFactory
 Contract Creation0 AVAX
248041862023-01-11 14:09:581033 days ago1673446198
Trader Joe: LBFactory
 Contract Creation0 AVAX
245482032023-01-05 11:37:421039 days ago1672918662
Trader Joe: LBFactory
 Contract Creation0 AVAX
239278662022-12-21 16:09:571054 days ago1671638997
Trader Joe: LBFactory
 Contract Creation0 AVAX
239278662022-12-21 16:09:571054 days ago1671638997
Trader Joe: LBFactory
 Contract Creation0 AVAX
238880582022-12-20 17:39:271055 days ago1671557967
Trader Joe: LBFactory
 Contract Creation0 AVAX
238880582022-12-20 17:39:271055 days ago1671557967
Trader Joe: LBFactory
 Contract Creation0 AVAX
230332292022-11-30 11:57:221075 days ago1669809442
Trader Joe: LBFactory
 Contract Creation0 AVAX
230332292022-11-30 11:57:221075 days ago1669809442
Trader Joe: LBFactory
 Contract Creation0 AVAX
230332292022-11-30 11:57:221075 days ago1669809442
Trader Joe: LBFactory
 Contract Creation0 AVAX
227073112022-11-22 17:43:461083 days ago1669139026
Trader Joe: LBFactory
 Contract Creation0 AVAX
227073112022-11-22 17:43:461083 days ago1669139026
Trader Joe: LBFactory
 Contract Creation0 AVAX
224424232022-11-16 8:30:561089 days ago1668587456
Trader Joe: LBFactory
 Contract Creation0 AVAX
View All Internal Transactions
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LBFactory

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 800 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/proxy/Clones.sol";
import "openzeppelin/utils/structs/EnumerableSet.sol";

import "./LBErrors.sol";
import "./libraries/BinHelper.sol";
import "./libraries/Constants.sol";
import "./libraries/Decoder.sol";
import "./libraries/PendingOwnable.sol";
import "./libraries/SafeCast.sol";
import "./interfaces/ILBFactory.sol";

/// @title Liquidity Book Factory
/// @author Trader Joe
/// @notice Contract used to deploy and register new LBPairs.
/// Enables setting fee parameters, flashloan fees and LBPair implementation.
/// Unless the `creationUnlocked` is `true`, only the owner of the factory can create pairs.
contract LBFactory is PendingOwnable, ILBFactory {
    using SafeCast for uint256;
    using Decoder for bytes32;
    using EnumerableSet for EnumerableSet.AddressSet;

    uint256 public constant override MAX_FEE = 0.1e18; // 10%

    uint256 public constant override MIN_BIN_STEP = 1; // 0.01%
    uint256 public constant override MAX_BIN_STEP = 100; // 1%, can't be greater than 247 for indexing reasons

    uint256 public constant override MAX_PROTOCOL_SHARE = 2_500; // 25%

    address public override LBPairImplementation;

    address public override feeRecipient;

    /// @notice Whether the createLBPair function is unlocked and can be called by anyone (true) or only by owner (false)
    bool public override creationUnlocked;

    uint256 public override flashLoanFee;

    ILBPair[] public override allLBPairs;

    /// @dev Mapping from a (tokenA, tokenB, binStep) to a LBPair. The tokens are ordered to save gas, but they can be
    /// in the reverse order in the actual pair. Always query one of the 2 tokens of the pair to assert the order of the 2 tokens
    mapping(IERC20 => mapping(IERC20 => mapping(uint256 => LBPairInformation))) private _LBPairsInfo;

    /// @dev Whether a preset was set or not, if the bit at `index` is 1, it means that the binStep `index` was set
    /// The max binStep set is 247. We use this method instead of an array to keep it ordered and to reduce gas
    bytes32 private _availablePresets;

    // The parameters presets
    mapping(uint256 => bytes32) private _presets;

    EnumerableSet.AddressSet private _quoteAssetWhitelist;

    /// @dev Whether a LBPair was created with a bin step, if the bit at `index` is 1, it means that the LBPair with binStep `index` exists
    /// The max binStep set is 247. We use this method instead of an array to keep it ordered and to reduce gas
    mapping(IERC20 => mapping(IERC20 => bytes32)) private _availableLBPairBinSteps;

    /// @notice Constructor
    /// @param _feeRecipient The address of the fee recipient
    /// @param _flashLoanFee The value of the fee for flash loan
    constructor(address _feeRecipient, uint256 _flashLoanFee) {
        if (_flashLoanFee > MAX_FEE) revert LBFactory__FlashLoanFeeAboveMax(_flashLoanFee, MAX_FEE);

        _setFeeRecipient(_feeRecipient);

        flashLoanFee = _flashLoanFee;
        emit FlashLoanFeeSet(0, _flashLoanFee);
    }

    /// @notice View function to return the number of LBPairs created
    /// @return The number of LBPair
    function getNumberOfLBPairs() external view override returns (uint256) {
        return allLBPairs.length;
    }

    /// @notice View function to return the number of quote assets whitelisted
    /// @return The number of quote assets
    function getNumberOfQuoteAssets() external view override returns (uint256) {
        return _quoteAssetWhitelist.length();
    }

    /// @notice View function to return the quote asset whitelisted at index `index`
    /// @param _index The index
    /// @return The address of the _quoteAsset at index `index`
    function getQuoteAsset(uint256 _index) external view override returns (IERC20) {
        return IERC20(_quoteAssetWhitelist.at(_index));
    }

    /// @notice View function to return whether a token is a quotedAsset (true) or not (false)
    /// @param _token The address of the asset
    /// @return Whether the token is a quote asset or not
    function isQuoteAsset(IERC20 _token) external view override returns (bool) {
        return _quoteAssetWhitelist.contains(address(_token));
    }

    /// @notice Returns the LBPairInformation if it exists,
    /// if not, then the address 0 is returned. The order doesn't matter
    /// @param _tokenA The address of the first token of the pair
    /// @param _tokenB The address of the second token of the pair
    /// @param _binStep The bin step of the LBPair
    /// @return The LBPairInformation
    function getLBPairInformation(
        IERC20 _tokenA,
        IERC20 _tokenB,
        uint256 _binStep
    ) external view override returns (LBPairInformation memory) {
        return _getLBPairInformation(_tokenA, _tokenB, _binStep);
    }

    /// @notice View function to return the different parameters of the preset
    /// @param _binStep The bin step of the preset
    /// @return baseFactor The base factor
    /// @return filterPeriod The filter period of the preset
    /// @return decayPeriod The decay period of the preset
    /// @return reductionFactor The reduction factor of the preset
    /// @return variableFeeControl The variable fee control of the preset
    /// @return protocolShare The protocol share of the preset
    /// @return maxVolatilityAccumulated The max volatility accumulated of the preset
    /// @return sampleLifetime The sample lifetime of the preset
    function getPreset(uint16 _binStep)
        external
        view
        override
        returns (
            uint256 baseFactor,
            uint256 filterPeriod,
            uint256 decayPeriod,
            uint256 reductionFactor,
            uint256 variableFeeControl,
            uint256 protocolShare,
            uint256 maxVolatilityAccumulated,
            uint256 sampleLifetime
        )
    {
        bytes32 _preset = _presets[_binStep];
        if (_preset == bytes32(0)) revert LBFactory__BinStepHasNoPreset(_binStep);

        uint256 _shift;

        // Safety check
        require(_binStep == _preset.decode(type(uint16).max, _shift));

        baseFactor = _preset.decode(type(uint16).max, _shift += 16);
        filterPeriod = _preset.decode(type(uint16).max, _shift += 16);
        decayPeriod = _preset.decode(type(uint16).max, _shift += 16);
        reductionFactor = _preset.decode(type(uint16).max, _shift += 16);
        variableFeeControl = _preset.decode(type(uint24).max, _shift += 16);
        protocolShare = _preset.decode(type(uint16).max, _shift += 24);
        maxVolatilityAccumulated = _preset.decode(type(uint24).max, _shift += 16);

        sampleLifetime = _preset.decode(type(uint16).max, 240);
    }

    /// @notice View function to return the list of available binStep with a preset
    /// @return presetsBinStep The list of binStep
    function getAllBinSteps() external view override returns (uint256[] memory presetsBinStep) {
        unchecked {
            bytes32 _avPresets = _availablePresets;
            uint256 _nbPresets = _avPresets.decode(type(uint8).max, 248);

            if (_nbPresets > 0) {
                presetsBinStep = new uint256[](_nbPresets);

                uint256 _index;
                for (uint256 i = MIN_BIN_STEP; i <= MAX_BIN_STEP; ++i) {
                    if (_avPresets.decode(1, i) == 1) {
                        presetsBinStep[_index] = i;
                        if (++_index == _nbPresets) break;
                    }
                }
            }
        }
    }

    /// @notice View function to return all the LBPair of a pair of tokens
    /// @param _tokenX The first token of the pair
    /// @param _tokenY The second token of the pair
    /// @return LBPairsAvailable The list of available LBPairs
    function getAllLBPairs(IERC20 _tokenX, IERC20 _tokenY)
        external
        view
        override
        returns (LBPairInformation[] memory LBPairsAvailable)
    {
        unchecked {
            (IERC20 _tokenA, IERC20 _tokenB) = _sortTokens(_tokenX, _tokenY);

            bytes32 _avLBPairBinSteps = _availableLBPairBinSteps[_tokenA][_tokenB];
            uint256 _nbAvailable = _avLBPairBinSteps.decode(type(uint8).max, 248);

            if (_nbAvailable > 0) {
                LBPairsAvailable = new LBPairInformation[](_nbAvailable);

                uint256 _index;
                for (uint256 i = MIN_BIN_STEP; i <= MAX_BIN_STEP; ++i) {
                    if (_avLBPairBinSteps.decode(1, i) == 1) {
                        LBPairInformation memory _LBPairInformation = _LBPairsInfo[_tokenA][_tokenB][i];

                        LBPairsAvailable[_index] = LBPairInformation({
                            binStep: i.safe16(),
                            LBPair: _LBPairInformation.LBPair,
                            createdByOwner: _LBPairInformation.createdByOwner,
                            ignoredForRouting: _LBPairInformation.ignoredForRouting
                        });
                        if (++_index == _nbAvailable) break;
                    }
                }
            }
        }
    }

    /// @notice Set the LBPair implementation address
    /// @dev Needs to be called by the owner
    /// @param _LBPairImplementation The address of the implementation
    function setLBPairImplementation(address _LBPairImplementation) external override onlyOwner {
        if (ILBPair(_LBPairImplementation).factory() != this)
            revert LBFactory__LBPairSafetyCheckFailed(_LBPairImplementation);

        address _oldLBPairImplementation = LBPairImplementation;
        if (_oldLBPairImplementation == _LBPairImplementation)
            revert LBFactory__SameImplementation(_LBPairImplementation);

        LBPairImplementation = _LBPairImplementation;

        emit LBPairImplementationSet(_oldLBPairImplementation, _LBPairImplementation);
    }

    /// @notice Create a liquidity bin LBPair for _tokenX and _tokenY
    /// @param _tokenX The address of the first token
    /// @param _tokenY The address of the second token
    /// @param _activeId The active id of the pair
    /// @param _binStep The bin step in basis point, used to calculate log(1 + binStep)
    /// @return _LBPair The address of the newly created LBPair
    function createLBPair(
        IERC20 _tokenX,
        IERC20 _tokenY,
        uint24 _activeId,
        uint16 _binStep
    ) external override returns (ILBPair _LBPair) {
        address _owner = owner();
        if (!creationUnlocked && msg.sender != _owner) revert LBFactory__FunctionIsLockedForUsers(msg.sender);

        address _LBPairImplementation = LBPairImplementation;

        if (_LBPairImplementation == address(0)) revert LBFactory__ImplementationNotSet();

        if (!_quoteAssetWhitelist.contains(address(_tokenY))) revert LBFactory__QuoteAssetNotWhitelisted(_tokenY);

        if (_tokenX == _tokenY) revert LBFactory__IdenticalAddresses(_tokenX);

        // safety check, making sure that the price can be calculated
        BinHelper.getPriceFromId(_activeId, _binStep);

        // We sort token for storage efficiency, only one input needs to be stored because they are sorted
        (IERC20 _tokenA, IERC20 _tokenB) = _sortTokens(_tokenX, _tokenY);
        // single check is sufficient
        if (address(_tokenA) == address(0)) revert LBFactory__AddressZero();
        if (address(_LBPairsInfo[_tokenA][_tokenB][_binStep].LBPair) != address(0))
            revert LBFactory__LBPairAlreadyExists(_tokenX, _tokenY, _binStep);

        bytes32 _preset = _presets[_binStep];
        if (_preset == bytes32(0)) revert LBFactory__BinStepHasNoPreset(_binStep);

        uint256 _sampleLifetime = _preset.decode(type(uint16).max, 240);
        // We remove the bits that are not part of the feeParameters
        _preset &= bytes32(uint256(type(uint144).max));

        bytes32 _salt = keccak256(abi.encode(_tokenA, _tokenB, _binStep));
        _LBPair = ILBPair(Clones.cloneDeterministic(_LBPairImplementation, _salt));

        _LBPair.initialize(_tokenX, _tokenY, _activeId, uint16(_sampleLifetime), _preset);

        _LBPairsInfo[_tokenA][_tokenB][_binStep] = LBPairInformation({
            binStep: _binStep,
            LBPair: _LBPair,
            createdByOwner: msg.sender == _owner,
            ignoredForRouting: false
        });

        allLBPairs.push(_LBPair);

        {
            bytes32 _avLBPairBinSteps = _availableLBPairBinSteps[_tokenA][_tokenB];
            // We add a 1 at bit `_binStep` as this binStep is now set
            _avLBPairBinSteps = bytes32(uint256(_avLBPairBinSteps) | (1 << _binStep));

            // Increase the number of lb pairs by 1
            _avLBPairBinSteps = bytes32(uint256(_avLBPairBinSteps) + (1 << 248));

            // Save the changes
            _availableLBPairBinSteps[_tokenA][_tokenB] = _avLBPairBinSteps;
        }

        emit LBPairCreated(_tokenX, _tokenY, _binStep, _LBPair, allLBPairs.length - 1);

        emit FeeParametersSet(
            msg.sender,
            _LBPair,
            _binStep,
            _preset.decode(type(uint16).max, 16),
            _preset.decode(type(uint16).max, 32),
            _preset.decode(type(uint16).max, 48),
            _preset.decode(type(uint16).max, 64),
            _preset.decode(type(uint24).max, 80),
            _preset.decode(type(uint16).max, 104),
            _preset.decode(type(uint24).max, 120)
        );
    }

    /// @notice Function to set whether the pair is ignored or not for routing, it will make the pair unusable by the router
    /// @param _tokenX The address of the first token of the pair
    /// @param _tokenY The address of the second token of the pair
    /// @param _binStep The bin step in basis point of the pair
    /// @param _ignored Whether to ignore (true) or not (false) the pair for routing
    function setLBPairIgnored(
        IERC20 _tokenX,
        IERC20 _tokenY,
        uint256 _binStep,
        bool _ignored
    ) external override onlyOwner {
        (IERC20 _tokenA, IERC20 _tokenB) = _sortTokens(_tokenX, _tokenY);

        LBPairInformation memory _LBPairInformation = _LBPairsInfo[_tokenA][_tokenB][_binStep];
        if (address(_LBPairInformation.LBPair) == address(0)) revert LBFactory__AddressZero();

        if (_LBPairInformation.ignoredForRouting == _ignored) revert LBFactory__LBPairIgnoredIsAlreadyInTheSameState();

        _LBPairsInfo[_tokenA][_tokenB][_binStep].ignoredForRouting = _ignored;

        emit LBPairIgnoredStateChanged(_LBPairInformation.LBPair, _ignored);
    }

    /// @notice Sets the preset parameters of a bin step
    /// @param _binStep The bin step in basis point, used to calculate log(1 + binStep)
    /// @param _baseFactor The base factor, used to calculate the base fee, baseFee = baseFactor * binStep
    /// @param _filterPeriod The period where the accumulator value is untouched, prevent spam
    /// @param _decayPeriod The period where the accumulator value is halved
    /// @param _reductionFactor The reduction factor, used to calculate the reduction of the accumulator
    /// @param _variableFeeControl The variable fee control, used to control the variable fee, can be 0 to disable it
    /// @param _protocolShare The share of the fees received by the protocol
    /// @param _maxVolatilityAccumulated The max value of the volatility accumulated
    /// @param _sampleLifetime The lifetime of an oracle's sample
    function setPreset(
        uint16 _binStep,
        uint16 _baseFactor,
        uint16 _filterPeriod,
        uint16 _decayPeriod,
        uint16 _reductionFactor,
        uint24 _variableFeeControl,
        uint16 _protocolShare,
        uint24 _maxVolatilityAccumulated,
        uint16 _sampleLifetime
    ) external override onlyOwner {
        bytes32 _packedFeeParameters = _getPackedFeeParameters(
            _binStep,
            _baseFactor,
            _filterPeriod,
            _decayPeriod,
            _reductionFactor,
            _variableFeeControl,
            _protocolShare,
            _maxVolatilityAccumulated
        );

        // The last 16 bits are reserved for sampleLifetime
        bytes32 _preset = bytes32(
            (uint256(_packedFeeParameters) & type(uint144).max) | (uint256(_sampleLifetime) << 240)
        );

        _presets[_binStep] = _preset;

        bytes32 _avPresets = _availablePresets;
        if (_avPresets.decode(1, _binStep) == 0) {
            // We add a 1 at bit `_binStep` as this binStep is now set
            _avPresets = bytes32(uint256(_avPresets) | (1 << _binStep));

            // Increase the number of preset by 1
            _avPresets = bytes32(uint256(_avPresets) + (1 << 248));

            // Save the changes
            _availablePresets = _avPresets;
        }

        emit PresetSet(
            _binStep,
            _baseFactor,
            _filterPeriod,
            _decayPeriod,
            _reductionFactor,
            _variableFeeControl,
            _protocolShare,
            _maxVolatilityAccumulated,
            _sampleLifetime
        );
    }

    /// @notice Remove the preset linked to a binStep
    /// @param _binStep The bin step to remove
    function removePreset(uint16 _binStep) external override onlyOwner {
        if (_presets[_binStep] == bytes32(0)) revert LBFactory__BinStepHasNoPreset(_binStep);

        // Set the bit `_binStep` to 0
        bytes32 _avPresets = _availablePresets;

        _avPresets &= bytes32(type(uint256).max - (1 << _binStep));
        _avPresets = bytes32(uint256(_avPresets) - (1 << 248));

        // Save the changes
        _availablePresets = _avPresets;
        delete _presets[_binStep];

        emit PresetRemoved(_binStep);
    }

    /// @notice Function to set the fee parameter of a LBPair
    /// @param _tokenX The address of the first token
    /// @param _tokenY The address of the second token
    /// @param _binStep The bin step in basis point, used to calculate log(1 + binStep)
    /// @param _baseFactor The base factor, used to calculate the base fee, baseFee = baseFactor * binStep
    /// @param _filterPeriod The period where the accumulator value is untouched, prevent spam
    /// @param _decayPeriod The period where the accumulator value is halved
    /// @param _reductionFactor The reduction factor, used to calculate the reduction of the accumulator
    /// @param _variableFeeControl The variable fee control, used to control the variable fee, can be 0 to disable it
    /// @param _protocolShare The share of the fees received by the protocol
    /// @param _maxVolatilityAccumulated The max value of volatility accumulated
    function setFeesParametersOnPair(
        IERC20 _tokenX,
        IERC20 _tokenY,
        uint16 _binStep,
        uint16 _baseFactor,
        uint16 _filterPeriod,
        uint16 _decayPeriod,
        uint16 _reductionFactor,
        uint24 _variableFeeControl,
        uint16 _protocolShare,
        uint24 _maxVolatilityAccumulated
    ) external override onlyOwner {
        ILBPair _LBPair = _getLBPairInformation(_tokenX, _tokenY, _binStep).LBPair;

        if (address(_LBPair) == address(0)) revert LBFactory__LBPairNotCreated(_tokenX, _tokenY, _binStep);

        bytes32 _packedFeeParameters = _getPackedFeeParameters(
            _binStep,
            _baseFactor,
            _filterPeriod,
            _decayPeriod,
            _reductionFactor,
            _variableFeeControl,
            _protocolShare,
            _maxVolatilityAccumulated
        );

        _LBPair.setFeesParameters(_packedFeeParameters);

        emit FeeParametersSet(
            msg.sender,
            _LBPair,
            _binStep,
            _baseFactor,
            _filterPeriod,
            _decayPeriod,
            _reductionFactor,
            _variableFeeControl,
            _protocolShare,
            _maxVolatilityAccumulated
        );
    }

    /// @notice Function to set the recipient of the fees. This address needs to be able to receive ERC20s
    /// @param _feeRecipient The address of the recipient
    function setFeeRecipient(address _feeRecipient) external override onlyOwner {
        _setFeeRecipient(_feeRecipient);
    }

    /// @notice Function to set the flash loan fee
    /// @param _flashLoanFee The value of the fee for flash loan
    function setFlashLoanFee(uint256 _flashLoanFee) external override onlyOwner {
        uint256 _oldFlashLoanFee = flashLoanFee;

        if (_oldFlashLoanFee == _flashLoanFee) revert LBFactory__SameFlashLoanFee(_flashLoanFee);
        if (_flashLoanFee > MAX_FEE) revert LBFactory__FlashLoanFeeAboveMax(_flashLoanFee, MAX_FEE);

        flashLoanFee = _flashLoanFee;
        emit FlashLoanFeeSet(_oldFlashLoanFee, _flashLoanFee);
    }

    /// @notice Function to set the creation restriction of the Factory
    /// @param _locked If the creation is restricted (true) or not (false)
    function setFactoryLockedState(bool _locked) external override onlyOwner {
        if (creationUnlocked != _locked) revert LBFactory__FactoryLockIsAlreadyInTheSameState();
        creationUnlocked = !_locked;
        emit FactoryLockedStatusUpdated(_locked);
    }

    /// @notice Function to add an asset to the whitelist of quote assets
    /// @param _quoteAsset The quote asset (e.g: AVAX, USDC...)
    function addQuoteAsset(IERC20 _quoteAsset) external override onlyOwner {
        if (!_quoteAssetWhitelist.add(address(_quoteAsset)))
            revert LBFactory__QuoteAssetAlreadyWhitelisted(_quoteAsset);

        emit QuoteAssetAdded(_quoteAsset);
    }

    /// @notice Function to remove an asset from the whitelist of quote assets
    /// @param _quoteAsset The quote asset (e.g: AVAX, USDC...)
    function removeQuoteAsset(IERC20 _quoteAsset) external override onlyOwner {
        if (!_quoteAssetWhitelist.remove(address(_quoteAsset))) revert LBFactory__QuoteAssetNotWhitelisted(_quoteAsset);

        emit QuoteAssetRemoved(_quoteAsset);
    }

    /// @notice Internal function to set the recipient of the fee
    /// @param _feeRecipient The address of the recipient
    function _setFeeRecipient(address _feeRecipient) internal {
        if (_feeRecipient == address(0)) revert LBFactory__AddressZero();

        address _oldFeeRecipient = feeRecipient;
        if (_oldFeeRecipient == _feeRecipient) revert LBFactory__SameFeeRecipient(_feeRecipient);

        feeRecipient = _feeRecipient;
        emit FeeRecipientSet(_oldFeeRecipient, _feeRecipient);
    }

    function forceDecay(ILBPair _LBPair) external override onlyOwner {
        _LBPair.forceDecay();
    }

    /// @notice Internal function to set the fee parameter of a LBPair
    /// @param _binStep The bin step in basis point, used to calculate log(1 + binStep)
    /// @param _baseFactor The base factor, used to calculate the base fee, baseFee = baseFactor * binStep
    /// @param _filterPeriod The period where the accumulator value is untouched, prevent spam
    /// @param _decayPeriod The period where the accumulator value is halved
    /// @param _reductionFactor The reduction factor, used to calculate the reduction of the accumulator
    /// @param _variableFeeControl The variable fee control, used to control the variable fee, can be 0 to disable it
    /// @param _protocolShare The share of the fees received by the protocol
    /// @param _maxVolatilityAccumulated The max value of volatility accumulated
    function _getPackedFeeParameters(
        uint16 _binStep,
        uint16 _baseFactor,
        uint16 _filterPeriod,
        uint16 _decayPeriod,
        uint16 _reductionFactor,
        uint24 _variableFeeControl,
        uint16 _protocolShare,
        uint24 _maxVolatilityAccumulated
    ) private pure returns (bytes32) {
        if (_binStep < MIN_BIN_STEP || _binStep > MAX_BIN_STEP)
            revert LBFactory__BinStepRequirementsBreached(MIN_BIN_STEP, _binStep, MAX_BIN_STEP);

        if (_filterPeriod >= _decayPeriod) revert LBFactory__DecreasingPeriods(_filterPeriod, _decayPeriod);

        if (_reductionFactor > Constants.BASIS_POINT_MAX)
            revert LBFactory__ReductionFactorOverflows(_reductionFactor, Constants.BASIS_POINT_MAX);

        if (_protocolShare > MAX_PROTOCOL_SHARE)
            revert LBFactory__ProtocolShareOverflows(_protocolShare, MAX_PROTOCOL_SHARE);

        {
            uint256 _baseFee = (uint256(_baseFactor) * _binStep) * 1e10;

            // Can't overflow as the max value is `max(uint24) * (max(uint24) * max(uint16)) ** 2 < max(uint104)`
            // It returns 18 decimals as:
            // decimals(variableFeeControl * (volatilityAccumulated * binStep)**2 / 100) = 4 + (4 + 4) * 2 - 2 = 18
            uint256 _prod = uint256(_maxVolatilityAccumulated) * _binStep;
            uint256 _maxVariableFee = (_prod * _prod * _variableFeeControl) / 100;

            if (_baseFee + _maxVariableFee > MAX_FEE)
                revert LBFactory__FeesAboveMax(_baseFee + _maxVariableFee, MAX_FEE);
        }

        /// @dev It's very important that the sum of the sizes of those values is exactly 256 bits
        /// here, (112 + 24) + 16 + 24 + 16 + 16 + 16 + 16 + 16 = 256
        return
            bytes32(
                abi.encodePacked(
                    uint136(_maxVolatilityAccumulated), // The first 112 bits are reserved for the dynamic parameters
                    _protocolShare,
                    _variableFeeControl,
                    _reductionFactor,
                    _decayPeriod,
                    _filterPeriod,
                    _baseFactor,
                    _binStep
                )
            );
    }

    /// @notice Returns the LBPairInformation if it exists,
    /// if not, then the address 0 is returned. The order doesn't matter
    /// @param _tokenA The address of the first token of the pair
    /// @param _tokenB The address of the second token of the pair
    /// @param _binStep The bin step of the LBPair
    /// @return The LBPairInformation
    function _getLBPairInformation(
        IERC20 _tokenA,
        IERC20 _tokenB,
        uint256 _binStep
    ) private view returns (LBPairInformation memory) {
        (_tokenA, _tokenB) = _sortTokens(_tokenA, _tokenB);
        return _LBPairsInfo[_tokenA][_tokenB][_binStep];
    }

    /// @notice Private view function to sort 2 tokens in ascending order
    /// @param _tokenA The first token
    /// @param _tokenB The second token
    /// @return The sorted first token
    /// @return The sorted second token
    function _sortTokens(IERC20 _tokenA, IERC20 _tokenB) private pure returns (IERC20, IERC20) {
        if (_tokenA > _tokenB) (_tokenA, _tokenB) = (_tokenB, _tokenA);
        return (_tokenA, _tokenB);
    }
}

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

pragma solidity ^0.8.0;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library Clones {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create(0, ptr, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create2(0, ptr, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
            mstore(add(ptr, 0x38), shl(0x60, deployer))
            mstore(add(ptr, 0x4c), salt)
            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
            predicted := keccak256(add(ptr, 0x37), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(address implementation, bytes32 salt)
        internal
        view
        returns (address predicted)
    {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.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);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/structs/EnumerableSet.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 *  Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable.
 *  See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 *  In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        return _values(set._inner);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

File 5 of 19 : LBErrors.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./interfaces/ILBPair.sol";

/** LBRouter errors */

error LBRouter__SenderIsNotWAVAX();
error LBRouter__PairNotCreated(address tokenX, address tokenY, uint256 binStep);
error LBRouter__WrongAmounts(uint256 amount, uint256 reserve);
error LBRouter__SwapOverflows(uint256 id);
error LBRouter__BrokenSwapSafetyCheck();
error LBRouter__NotFactoryOwner();
error LBRouter__TooMuchTokensIn(uint256 excess);
error LBRouter__BinReserveOverflows(uint256 id);
error LBRouter__IdOverflows(int256 id);
error LBRouter__LengthsMismatch();
error LBRouter__WrongTokenOrder();
error LBRouter__IdSlippageCaught(uint256 activeIdDesired, uint256 idSlippage, uint256 activeId);
error LBRouter__AmountSlippageCaught(uint256 amountXMin, uint256 amountX, uint256 amountYMin, uint256 amountY);
error LBRouter__IdDesiredOverflows(uint256 idDesired, uint256 idSlippage);
error LBRouter__FailedToSendAVAX(address recipient, uint256 amount);
error LBRouter__DeadlineExceeded(uint256 deadline, uint256 currentTimestamp);
error LBRouter__AmountSlippageBPTooBig(uint256 amountSlippage);
error LBRouter__InsufficientAmountOut(uint256 amountOutMin, uint256 amountOut);
error LBRouter__MaxAmountInExceeded(uint256 amountInMax, uint256 amountIn);
error LBRouter__InvalidTokenPath(address wrongToken);
error LBRouter__InvalidVersion(uint256 version);
error LBRouter__WrongAvaxLiquidityParameters(
    address tokenX,
    address tokenY,
    uint256 amountX,
    uint256 amountY,
    uint256 msgValue
);

/** LBToken errors */

error LBToken__SpenderNotApproved(address owner, address spender);
error LBToken__TransferFromOrToAddress0();
error LBToken__MintToAddress0();
error LBToken__BurnFromAddress0();
error LBToken__BurnExceedsBalance(address from, uint256 id, uint256 amount);
error LBToken__LengthMismatch(uint256 accountsLength, uint256 idsLength);
error LBToken__SelfApproval(address owner);
error LBToken__TransferExceedsBalance(address from, uint256 id, uint256 amount);
error LBToken__TransferToSelf();

/** LBFactory errors */

error LBFactory__IdenticalAddresses(IERC20 token);
error LBFactory__QuoteAssetNotWhitelisted(IERC20 quoteAsset);
error LBFactory__QuoteAssetAlreadyWhitelisted(IERC20 quoteAsset);
error LBFactory__AddressZero();
error LBFactory__LBPairAlreadyExists(IERC20 tokenX, IERC20 tokenY, uint256 _binStep);
error LBFactory__LBPairNotCreated(IERC20 tokenX, IERC20 tokenY, uint256 binStep);
error LBFactory__DecreasingPeriods(uint16 filterPeriod, uint16 decayPeriod);
error LBFactory__ReductionFactorOverflows(uint16 reductionFactor, uint256 max);
error LBFactory__VariableFeeControlOverflows(uint16 variableFeeControl, uint256 max);
error LBFactory__BaseFeesBelowMin(uint256 baseFees, uint256 minBaseFees);
error LBFactory__FeesAboveMax(uint256 fees, uint256 maxFees);
error LBFactory__FlashLoanFeeAboveMax(uint256 fees, uint256 maxFees);
error LBFactory__BinStepRequirementsBreached(uint256 lowerBound, uint16 binStep, uint256 higherBound);
error LBFactory__ProtocolShareOverflows(uint16 protocolShare, uint256 max);
error LBFactory__FunctionIsLockedForUsers(address user);
error LBFactory__FactoryLockIsAlreadyInTheSameState();
error LBFactory__LBPairIgnoredIsAlreadyInTheSameState();
error LBFactory__BinStepHasNoPreset(uint256 binStep);
error LBFactory__SameFeeRecipient(address feeRecipient);
error LBFactory__SameFlashLoanFee(uint256 flashLoanFee);
error LBFactory__LBPairSafetyCheckFailed(address LBPairImplementation);
error LBFactory__SameImplementation(address LBPairImplementation);
error LBFactory__ImplementationNotSet();

/** LBPair errors */

error LBPair__InsufficientAmounts();
error LBPair__AddressZero();
error LBPair__AddressZeroOrThis();
error LBPair__CompositionFactorFlawed(uint256 id);
error LBPair__InsufficientLiquidityMinted(uint256 id);
error LBPair__InsufficientLiquidityBurned(uint256 id);
error LBPair__WrongLengths();
error LBPair__OnlyStrictlyIncreasingId();
error LBPair__OnlyFactory();
error LBPair__DistributionsOverflow();
error LBPair__OnlyFeeRecipient(address feeRecipient, address sender);
error LBPair__OracleNotEnoughSample();
error LBPair__AlreadyInitialized();
error LBPair__OracleNewSizeTooSmall(uint256 newSize, uint256 oracleSize);
error LBPair__FlashLoanCallbackFailed();
error LBPair__FlashLoanInvalidBalance();
error LBPair__FlashLoanInvalidToken();

/** BinHelper errors */

error BinHelper__BinStepOverflows(uint256 bp);
error BinHelper__IdOverflows();

/** Math128x128 errors */

error Math128x128__PowerUnderflow(uint256 x, int256 y);
error Math128x128__LogUnderflow();

/** Math512Bits errors */

error Math512Bits__MulDivOverflow(uint256 prod1, uint256 denominator);
error Math512Bits__ShiftDivOverflow(uint256 prod1, uint256 denominator);
error Math512Bits__MulShiftOverflow(uint256 prod1, uint256 offset);
error Math512Bits__OffsetOverflows(uint256 offset);

/** Oracle errors */

error Oracle__AlreadyInitialized(uint256 _index);
error Oracle__LookUpTimestampTooOld(uint256 _minTimestamp, uint256 _lookUpTimestamp);
error Oracle__NotInitialized();

/** PendingOwnable errors */

error PendingOwnable__NotOwner();
error PendingOwnable__NotPendingOwner();
error PendingOwnable__PendingOwnerAlreadySet();
error PendingOwnable__NoPendingOwner();
error PendingOwnable__AddressZero();

/** ReentrancyGuardUpgradeable errors */

error ReentrancyGuardUpgradeable__ReentrantCall();
error ReentrancyGuardUpgradeable__AlreadyInitialized();

/** SafeCast errors */

error SafeCast__Exceeds256Bits(uint256 x);
error SafeCast__Exceeds248Bits(uint256 x);
error SafeCast__Exceeds240Bits(uint256 x);
error SafeCast__Exceeds232Bits(uint256 x);
error SafeCast__Exceeds224Bits(uint256 x);
error SafeCast__Exceeds216Bits(uint256 x);
error SafeCast__Exceeds208Bits(uint256 x);
error SafeCast__Exceeds200Bits(uint256 x);
error SafeCast__Exceeds192Bits(uint256 x);
error SafeCast__Exceeds184Bits(uint256 x);
error SafeCast__Exceeds176Bits(uint256 x);
error SafeCast__Exceeds168Bits(uint256 x);
error SafeCast__Exceeds160Bits(uint256 x);
error SafeCast__Exceeds152Bits(uint256 x);
error SafeCast__Exceeds144Bits(uint256 x);
error SafeCast__Exceeds136Bits(uint256 x);
error SafeCast__Exceeds128Bits(uint256 x);
error SafeCast__Exceeds120Bits(uint256 x);
error SafeCast__Exceeds112Bits(uint256 x);
error SafeCast__Exceeds104Bits(uint256 x);
error SafeCast__Exceeds96Bits(uint256 x);
error SafeCast__Exceeds88Bits(uint256 x);
error SafeCast__Exceeds80Bits(uint256 x);
error SafeCast__Exceeds72Bits(uint256 x);
error SafeCast__Exceeds64Bits(uint256 x);
error SafeCast__Exceeds56Bits(uint256 x);
error SafeCast__Exceeds48Bits(uint256 x);
error SafeCast__Exceeds40Bits(uint256 x);
error SafeCast__Exceeds32Bits(uint256 x);
error SafeCast__Exceeds24Bits(uint256 x);
error SafeCast__Exceeds16Bits(uint256 x);
error SafeCast__Exceeds8Bits(uint256 x);

/** TreeMath errors */

error TreeMath__ErrorDepthSearch();

/** JoeLibrary errors */

error JoeLibrary__IdenticalAddresses();
error JoeLibrary__AddressZero();
error JoeLibrary__InsufficientAmount();
error JoeLibrary__InsufficientLiquidity();

/** TokenHelper errors */

error TokenHelper__NonContract();
error TokenHelper__CallFailed();
error TokenHelper__TransferFailed();

/** LBQuoter errors */

error LBQuoter_InvalidLength();

// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/token/ERC20/IERC20.sol";

import "./ILBPair.sol";
import "./IPendingOwnable.sol";

/// @title Liquidity Book Factory Interface
/// @author Trader Joe
/// @notice Required interface of LBFactory contract
interface ILBFactory is IPendingOwnable {
    /// @dev Structure to store the LBPair information, such as:
    /// - binStep: The bin step of the LBPair
    /// - LBPair: The address of the LBPair
    /// - createdByOwner: Whether the pair was created by the owner of the factory
    /// - ignoredForRouting: Whether the pair is ignored for routing or not. An ignored pair will not be explored during routes finding
    struct LBPairInformation {
        uint16 binStep;
        ILBPair LBPair;
        bool createdByOwner;
        bool ignoredForRouting;
    }

    event LBPairCreated(
        IERC20 indexed tokenX,
        IERC20 indexed tokenY,
        uint256 indexed binStep,
        ILBPair LBPair,
        uint256 pid
    );

    event FeeRecipientSet(address oldRecipient, address newRecipient);

    event FlashLoanFeeSet(uint256 oldFlashLoanFee, uint256 newFlashLoanFee);

    event FeeParametersSet(
        address indexed sender,
        ILBPair indexed LBPair,
        uint256 binStep,
        uint256 baseFactor,
        uint256 filterPeriod,
        uint256 decayPeriod,
        uint256 reductionFactor,
        uint256 variableFeeControl,
        uint256 protocolShare,
        uint256 maxVolatilityAccumulated
    );

    event FactoryLockedStatusUpdated(bool unlocked);

    event LBPairImplementationSet(address oldLBPairImplementation, address LBPairImplementation);

    event LBPairIgnoredStateChanged(ILBPair indexed LBPair, bool ignored);

    event PresetSet(
        uint256 indexed binStep,
        uint256 baseFactor,
        uint256 filterPeriod,
        uint256 decayPeriod,
        uint256 reductionFactor,
        uint256 variableFeeControl,
        uint256 protocolShare,
        uint256 maxVolatilityAccumulated,
        uint256 sampleLifetime
    );

    event PresetRemoved(uint256 indexed binStep);

    event QuoteAssetAdded(IERC20 indexed quoteAsset);

    event QuoteAssetRemoved(IERC20 indexed quoteAsset);

    function MAX_FEE() external pure returns (uint256);

    function MIN_BIN_STEP() external pure returns (uint256);

    function MAX_BIN_STEP() external pure returns (uint256);

    function MAX_PROTOCOL_SHARE() external pure returns (uint256);

    function LBPairImplementation() external view returns (address);

    function getNumberOfQuoteAssets() external view returns (uint256);

    function getQuoteAsset(uint256 index) external view returns (IERC20);

    function isQuoteAsset(IERC20 token) external view returns (bool);

    function feeRecipient() external view returns (address);

    function flashLoanFee() external view returns (uint256);

    function creationUnlocked() external view returns (bool);

    function allLBPairs(uint256 id) external returns (ILBPair);

    function getNumberOfLBPairs() external view returns (uint256);

    function getLBPairInformation(
        IERC20 tokenX,
        IERC20 tokenY,
        uint256 binStep
    ) external view returns (LBPairInformation memory);

    function getPreset(uint16 binStep)
        external
        view
        returns (
            uint256 baseFactor,
            uint256 filterPeriod,
            uint256 decayPeriod,
            uint256 reductionFactor,
            uint256 variableFeeControl,
            uint256 protocolShare,
            uint256 maxAccumulator,
            uint256 sampleLifetime
        );

    function getAllBinSteps() external view returns (uint256[] memory presetsBinStep);

    function getAllLBPairs(IERC20 tokenX, IERC20 tokenY)
        external
        view
        returns (LBPairInformation[] memory LBPairsBinStep);

    function setLBPairImplementation(address LBPairImplementation) external;

    function createLBPair(
        IERC20 tokenX,
        IERC20 tokenY,
        uint24 activeId,
        uint16 binStep
    ) external returns (ILBPair pair);

    function setLBPairIgnored(
        IERC20 tokenX,
        IERC20 tokenY,
        uint256 binStep,
        bool ignored
    ) external;

    function setPreset(
        uint16 binStep,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulated,
        uint16 sampleLifetime
    ) external;

    function removePreset(uint16 binStep) external;

    function setFeesParametersOnPair(
        IERC20 tokenX,
        IERC20 tokenY,
        uint16 binStep,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulated
    ) external;

    function setFeeRecipient(address feeRecipient) external;

    function setFlashLoanFee(uint256 flashLoanFee) external;

    function setFactoryLockedState(bool locked) external;

    function addQuoteAsset(IERC20 quoteAsset) external;

    function removeQuoteAsset(IERC20 quoteAsset) external;

    function forceDecay(ILBPair LBPair) external;
}

File 7 of 19 : ILBFlashLoanCallback.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/token/ERC20/IERC20.sol";

/// @title Liquidity Book Flashloan Callback Interface
/// @author Trader Joe
/// @notice Required interface to interact with LB flash loans
interface ILBFlashLoanCallback {
    function LBFlashLoanCallback(
        address sender,
        IERC20 token,
        uint256 amount,
        uint256 fee,
        bytes calldata data
    ) external returns (bytes32);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/token/ERC20/IERC20.sol";

import "../libraries/FeeHelper.sol";
import "./ILBFactory.sol";
import "./ILBFlashLoanCallback.sol";

/// @title Liquidity Book Pair Interface
/// @author Trader Joe
/// @notice Required interface of LBPair contract
interface ILBPair {
    /// @dev Structure to store the reserves of bins:
    /// - reserveX: The current reserve of tokenX of the bin
    /// - reserveY: The current reserve of tokenY of the bin
    struct Bin {
        uint112 reserveX;
        uint112 reserveY;
        uint256 accTokenXPerShare;
        uint256 accTokenYPerShare;
    }

    /// @dev Structure to store the information of the pair such as:
    /// slot0:
    /// - activeId: The current id used for swaps, this is also linked with the price
    /// - reserveX: The sum of amounts of tokenX across all bins
    /// slot1:
    /// - reserveY: The sum of amounts of tokenY across all bins
    /// - oracleSampleLifetime: The lifetime of an oracle sample
    /// - oracleSize: The current size of the oracle, can be increase by users
    /// - oracleActiveSize: The current active size of the oracle, composed only from non empty data sample
    /// - oracleLastTimestamp: The current last timestamp at which a sample was added to the circular buffer
    /// - oracleId: The current id of the oracle
    /// slot2:
    /// - feesX: The current amount of fees to distribute in tokenX (total, protocol)
    /// slot3:
    /// - feesY: The current amount of fees to distribute in tokenY (total, protocol)
    struct PairInformation {
        uint24 activeId;
        uint136 reserveX;
        uint136 reserveY;
        uint16 oracleSampleLifetime;
        uint16 oracleSize;
        uint16 oracleActiveSize;
        uint40 oracleLastTimestamp;
        uint16 oracleId;
        FeeHelper.FeesDistribution feesX;
        FeeHelper.FeesDistribution feesY;
    }

    /// @dev Structure to store the debts of users
    /// - debtX: The tokenX's debt
    /// - debtY: The tokenY's debt
    struct Debts {
        uint256 debtX;
        uint256 debtY;
    }

    /// @dev Structure to store fees:
    /// - tokenX: The amount of fees of token X
    /// - tokenY: The amount of fees of token Y
    struct Fees {
        uint128 tokenX;
        uint128 tokenY;
    }

    /// @dev Structure to minting informations:
    /// - amountXIn: The amount of token X sent
    /// - amountYIn: The amount of token Y sent
    /// - amountXAddedToPair: The amount of token X that have been actually added to the pair
    /// - amountYAddedToPair: The amount of token Y that have been actually added to the pair
    /// - activeFeeX: Fees X currently generated
    /// - activeFeeY: Fees Y currently generated
    /// - totalDistributionX: Total distribution of token X. Should be 1e18 (100%) or 0 (0%)
    /// - totalDistributionY: Total distribution of token Y. Should be 1e18 (100%) or 0 (0%)
    /// - id: Id of the current working bin when looping on the distribution array
    /// - amountX: The amount of token X deposited in the current bin
    /// - amountY: The amount of token Y deposited in the current bin
    /// - distributionX: Distribution of token X for the current working bin
    /// - distributionY: Distribution of token Y for the current working bin
    struct MintInfo {
        uint256 amountXIn;
        uint256 amountYIn;
        uint256 amountXAddedToPair;
        uint256 amountYAddedToPair;
        uint256 activeFeeX;
        uint256 activeFeeY;
        uint256 totalDistributionX;
        uint256 totalDistributionY;
        uint256 id;
        uint256 amountX;
        uint256 amountY;
        uint256 distributionX;
        uint256 distributionY;
    }

    event Swap(
        address indexed sender,
        address indexed recipient,
        uint256 indexed id,
        bool swapForY,
        uint256 amountIn,
        uint256 amountOut,
        uint256 volatilityAccumulated,
        uint256 fees
    );

    event FlashLoan(
        address indexed sender,
        ILBFlashLoanCallback indexed receiver,
        IERC20 token,
        uint256 amount,
        uint256 fee
    );

    event CompositionFee(
        address indexed sender,
        address indexed recipient,
        uint256 indexed id,
        uint256 feesX,
        uint256 feesY
    );

    event DepositedToBin(
        address indexed sender,
        address indexed recipient,
        uint256 indexed id,
        uint256 amountX,
        uint256 amountY
    );

    event WithdrawnFromBin(
        address indexed sender,
        address indexed recipient,
        uint256 indexed id,
        uint256 amountX,
        uint256 amountY
    );

    event FeesCollected(address indexed sender, address indexed recipient, uint256 amountX, uint256 amountY);

    event ProtocolFeesCollected(address indexed sender, address indexed recipient, uint256 amountX, uint256 amountY);

    event OracleSizeIncreased(uint256 previousSize, uint256 newSize);

    function tokenX() external view returns (IERC20);

    function tokenY() external view returns (IERC20);

    function factory() external view returns (ILBFactory);

    function getReservesAndId()
        external
        view
        returns (
            uint256 reserveX,
            uint256 reserveY,
            uint256 activeId
        );

    function getGlobalFees()
        external
        view
        returns (
            uint128 feesXTotal,
            uint128 feesYTotal,
            uint128 feesXProtocol,
            uint128 feesYProtocol
        );

    function getOracleParameters()
        external
        view
        returns (
            uint256 oracleSampleLifetime,
            uint256 oracleSize,
            uint256 oracleActiveSize,
            uint256 oracleLastTimestamp,
            uint256 oracleId,
            uint256 min,
            uint256 max
        );

    function getOracleSampleFrom(uint256 timeDelta)
        external
        view
        returns (
            uint256 cumulativeId,
            uint256 cumulativeAccumulator,
            uint256 cumulativeBinCrossed
        );

    function feeParameters() external view returns (FeeHelper.FeeParameters memory);

    function findFirstNonEmptyBinId(uint24 id_, bool sentTokenY) external view returns (uint24 id);

    function getBin(uint24 id) external view returns (uint256 reserveX, uint256 reserveY);

    function pendingFees(address account, uint256[] memory ids)
        external
        view
        returns (uint256 amountX, uint256 amountY);

    function swap(bool sentTokenY, address to) external returns (uint256 amountXOut, uint256 amountYOut);

    function flashLoan(
        ILBFlashLoanCallback receiver,
        IERC20 token,
        uint256 amount,
        bytes calldata data
    ) external;

    function mint(
        uint256[] calldata ids,
        uint256[] calldata distributionX,
        uint256[] calldata distributionY,
        address to
    )
        external
        returns (
            uint256 amountXAddedToPair,
            uint256 amountYAddedToPair,
            uint256[] memory liquidityMinted
        );

    function burn(
        uint256[] calldata ids,
        uint256[] calldata amounts,
        address to
    ) external returns (uint256 amountX, uint256 amountY);

    function increaseOracleLength(uint16 newSize) external;

    function collectFees(address account, uint256[] calldata ids) external returns (uint256 amountX, uint256 amountY);

    function collectProtocolFees() external returns (uint128 amountX, uint128 amountY);

    function setFeesParameters(bytes32 packedFeeParameters) external;

    function forceDecay() external;

    function initialize(
        IERC20 tokenX,
        IERC20 tokenY,
        uint24 activeId,
        uint16 sampleLifetime,
        bytes32 packedFeeParameters
    ) external;
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/// @title Liquidity Book Pending Ownable Interface
/// @author Trader Joe
/// @notice Required interface of Pending Ownable contract used for LBFactory
interface IPendingOwnable {
    event PendingOwnerSet(address indexed pendingOwner);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    function owner() external view returns (address);

    function pendingOwner() external view returns (address);

    function setPendingOwner(address pendingOwner) external;

    function revokePendingOwner() external;

    function becomeOwner() external;

    function renounceOwnership() external;
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";
import "./Math128x128.sol";

/// @title Liquidity Book Bin Helper Library
/// @author Trader Joe
/// @notice Contract used to convert bin ID to price and back
library BinHelper {
    using Math128x128 for uint256;

    int256 private constant REAL_ID_SHIFT = 1 << 23;

    /// @notice Returns the id corresponding to the given price
    /// @dev The id may be inaccurate due to rounding issues, always trust getPriceFromId rather than
    /// getIdFromPrice
    /// @param _price The price of y per x as a 128.128-binary fixed-point number
    /// @param _binStep The bin step
    /// @return The id corresponding to this price
    function getIdFromPrice(uint256 _price, uint256 _binStep) internal pure returns (uint24) {
        unchecked {
            uint256 _binStepValue = _getBPValue(_binStep);

            // can't overflow as `2**23 + log2(price) < 2**23 + 2**128 < max(uint256)`
            int256 _id = REAL_ID_SHIFT + _price.log2() / _binStepValue.log2();

            if (_id < 0 || uint256(_id) > type(uint24).max) revert BinHelper__IdOverflows();
            return uint24(uint256(_id));
        }
    }

    /// @notice Returns the price corresponding to the given ID, as a 128.128-binary fixed-point number
    /// @dev This is the trusted function to link id to price, the other way may be inaccurate
    /// @param _id The id
    /// @param _binStep The bin step
    /// @return The price corresponding to this id, as a 128.128-binary fixed-point number
    function getPriceFromId(uint256 _id, uint256 _binStep) internal pure returns (uint256) {
        if (_id > uint256(type(uint24).max)) revert BinHelper__IdOverflows();
        unchecked {
            int256 _realId = int256(_id) - REAL_ID_SHIFT;

            return _getBPValue(_binStep).power(_realId);
        }
    }

    /// @notice Returns the (1 + bp) value as a 128.128-decimal fixed-point number
    /// @param _binStep The bp value in [1; 100] (referring to 0.01% to 1%)
    /// @return The (1+bp) value as a 128.128-decimal fixed-point number
    function _getBPValue(uint256 _binStep) internal pure returns (uint256) {
        if (_binStep == 0 || _binStep > Constants.BASIS_POINT_MAX) revert BinHelper__BinStepOverflows(_binStep);

        unchecked {
            // can't overflow as `max(result) = 2**128 + 10_000 << 128 / 10_000 < max(uint256)`
            return Constants.SCALE + (_binStep << Constants.SCALE_OFFSET) / Constants.BASIS_POINT_MAX;
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/// @title Liquidity Book Bit Math Library
/// @author Trader Joe
/// @notice Helper contract used for bit calculations
library BitMath {
    /// @notice Returns the closest non-zero bit of `integer` to the right (of left) of the `bit` bits that is not `bit`
    /// @param _integer The integer as a uint256
    /// @param _bit The bit index
    /// @param _rightSide Whether we're searching in the right side of the tree (true) or the left side (false)
    /// @return The index of the closest non-zero bit. If there is no closest bit, it returns max(uint256)
    function closestBit(
        uint256 _integer,
        uint8 _bit,
        bool _rightSide
    ) internal pure returns (uint256) {
        return _rightSide ? closestBitRight(_integer, _bit - 1) : closestBitLeft(_integer, _bit + 1);
    }

    /// @notice Returns the most (or least) significant bit of `_integer`
    /// @param _integer The integer
    /// @param _isMostSignificant Whether we want the most (true) or the least (false) significant bit
    /// @return The index of the most (or least) significant bit
    function significantBit(uint256 _integer, bool _isMostSignificant) internal pure returns (uint8) {
        return _isMostSignificant ? mostSignificantBit(_integer) : leastSignificantBit(_integer);
    }

    /// @notice Returns the index of the closest bit on the right of x that is non null
    /// @param x The value as a uint256
    /// @param bit The index of the bit to start searching at
    /// @return id The index of the closest non null bit on the right of x.
    /// If there is no closest bit, it returns max(uint256)
    function closestBitRight(uint256 x, uint8 bit) internal pure returns (uint256 id) {
        unchecked {
            uint256 _shift = 255 - bit;
            x <<= _shift;

            // can't overflow as it's non-zero and we shifted it by `_shift`
            return (x == 0) ? type(uint256).max : mostSignificantBit(x) - _shift;
        }
    }

    /// @notice Returns the index of the closest bit on the left of x that is non null
    /// @param x The value as a uint256
    /// @param bit The index of the bit to start searching at
    /// @return id The index of the closest non null bit on the left of x.
    /// If there is no closest bit, it returns max(uint256)
    function closestBitLeft(uint256 x, uint8 bit) internal pure returns (uint256 id) {
        unchecked {
            x >>= bit;

            return (x == 0) ? type(uint256).max : leastSignificantBit(x) + bit;
        }
    }

    /// @notice Returns the index of the most significant bit of x
    /// @param x The value as a uint256
    /// @return msb The index of the most significant bit of x
    function mostSignificantBit(uint256 x) internal pure returns (uint8 msb) {
        unchecked {
            if (x >= 1 << 128) {
                x >>= 128;
                msb = 128;
            }
            if (x >= 1 << 64) {
                x >>= 64;
                msb += 64;
            }
            if (x >= 1 << 32) {
                x >>= 32;
                msb += 32;
            }
            if (x >= 1 << 16) {
                x >>= 16;
                msb += 16;
            }
            if (x >= 1 << 8) {
                x >>= 8;
                msb += 8;
            }
            if (x >= 1 << 4) {
                x >>= 4;
                msb += 4;
            }
            if (x >= 1 << 2) {
                x >>= 2;
                msb += 2;
            }
            if (x >= 1 << 1) {
                msb += 1;
            }
        }
    }

    /// @notice Returns the index of the least significant bit of x
    /// @param x The value as a uint256
    /// @return lsb The index of the least significant bit of x
    function leastSignificantBit(uint256 x) internal pure returns (uint8 lsb) {
        unchecked {
            if (x << 128 != 0) {
                x <<= 128;
                lsb = 128;
            }
            if (x << 64 != 0) {
                x <<= 64;
                lsb += 64;
            }
            if (x << 32 != 0) {
                x <<= 32;
                lsb += 32;
            }
            if (x << 16 != 0) {
                x <<= 16;
                lsb += 16;
            }
            if (x << 8 != 0) {
                x <<= 8;
                lsb += 8;
            }
            if (x << 4 != 0) {
                x <<= 4;
                lsb += 4;
            }
            if (x << 2 != 0) {
                x <<= 2;
                lsb += 2;
            }
            if (x << 1 != 0) {
                lsb += 1;
            }

            return 255 - lsb;
        }
    }
}

File 12 of 19 : Constants.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/// @title Liquidity Book Constants Library
/// @author Trader Joe
/// @notice Set of constants for Liquidity Book contracts
library Constants {
    uint256 internal constant SCALE_OFFSET = 128;
    uint256 internal constant SCALE = 1 << SCALE_OFFSET;

    uint256 internal constant PRECISION = 1e18;
    uint256 internal constant BASIS_POINT_MAX = 10_000;

    /// @dev The expected return after a successful flash loan
    bytes32 internal constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
}

File 13 of 19 : Decoder.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/// @title Liquidity Book Decoder Library
/// @author Trader Joe
/// @notice Helper contract used for decoding bytes32 sample
library Decoder {
    /// @notice Internal function to decode a bytes32 sample using a mask and offset
    /// @dev This function can overflow
    /// @param _sample The sample as a bytes32
    /// @param _mask The mask
    /// @param _offset The offset
    /// @return value The decoded value
    function decode(
        bytes32 _sample,
        uint256 _mask,
        uint256 _offset
    ) internal pure returns (uint256 value) {
        assembly {
            value := and(shr(_offset, _sample), _mask)
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./Constants.sol";
import "./SafeCast.sol";
import "./SafeMath.sol";

/// @title Liquidity Book Fee Helper Library
/// @author Trader Joe
/// @notice Helper contract used for fees calculation
library FeeHelper {
    using SafeCast for uint256;
    using SafeMath for uint256;

    /// @dev Structure to store the protocol fees:
    /// - binStep: The bin step
    /// - baseFactor: The base factor
    /// - filterPeriod: The filter period, where the fees stays constant
    /// - decayPeriod: The decay period, where the fees are halved
    /// - reductionFactor: The reduction factor, used to calculate the reduction of the accumulator
    /// - variableFeeControl: The variable fee control, used to control the variable fee, can be 0 to disable them
    /// - protocolShare: The share of fees sent to protocol
    /// - maxVolatilityAccumulated: The max value of volatility accumulated
    /// - volatilityAccumulated: The value of volatility accumulated
    /// - volatilityReference: The value of volatility reference
    /// - indexRef: The index reference
    /// - time: The last time the accumulator was called
    struct FeeParameters {
        // 144 lowest bits in slot
        uint16 binStep;
        uint16 baseFactor;
        uint16 filterPeriod;
        uint16 decayPeriod;
        uint16 reductionFactor;
        uint24 variableFeeControl;
        uint16 protocolShare;
        uint24 maxVolatilityAccumulated;
        // 112 highest bits in slot
        uint24 volatilityAccumulated;
        uint24 volatilityReference;
        uint24 indexRef;
        uint40 time;
    }

    /// @dev Structure used during swaps to distributes the fees:
    /// - total: The total amount of fees
    /// - protocol: The amount of fees reserved for protocol
    struct FeesDistribution {
        uint128 total;
        uint128 protocol;
    }

    /// @notice Update the value of the volatility accumulated
    /// @param _fp The current fee parameters
    /// @param _activeId The current active id
    function updateVariableFeeParameters(FeeParameters memory _fp, uint256 _activeId) internal view {
        uint256 _deltaT = block.timestamp - _fp.time;

        if (_deltaT >= _fp.filterPeriod || _fp.time == 0) {
            _fp.indexRef = uint24(_activeId);
            if (_deltaT < _fp.decayPeriod) {
                unchecked {
                    // This can't overflow as `reductionFactor <= BASIS_POINT_MAX`
                    _fp.volatilityReference = uint24(
                        (uint256(_fp.reductionFactor) * _fp.volatilityAccumulated) / Constants.BASIS_POINT_MAX
                    );
                }
            } else {
                _fp.volatilityReference = 0;
            }
        }

        _fp.time = (block.timestamp).safe40();

        updateVolatilityAccumulated(_fp, _activeId);
    }

    /// @notice Update the volatility accumulated
    /// @param _fp The fee parameter
    /// @param _activeId The current active id
    function updateVolatilityAccumulated(FeeParameters memory _fp, uint256 _activeId) internal pure {
        uint256 volatilityAccumulated = (_activeId.absSub(_fp.indexRef) * Constants.BASIS_POINT_MAX) +
            _fp.volatilityReference;
        _fp.volatilityAccumulated = volatilityAccumulated > _fp.maxVolatilityAccumulated
            ? _fp.maxVolatilityAccumulated
            : uint24(volatilityAccumulated);
    }

    /// @notice Returns the base fee added to a swap, with 18 decimals
    /// @param _fp The current fee parameters
    /// @return The fee with 18 decimals precision
    function getBaseFee(FeeParameters memory _fp) internal pure returns (uint256) {
        unchecked {
            return uint256(_fp.baseFactor) * _fp.binStep * 1e10;
        }
    }

    /// @notice Returns the variable fee added to a swap, with 18 decimals
    /// @param _fp The current fee parameters
    /// @return variableFee The variable fee with 18 decimals precision
    function getVariableFee(FeeParameters memory _fp) internal pure returns (uint256 variableFee) {
        if (_fp.variableFeeControl != 0) {
            // Can't overflow as the max value is `max(uint24) * (max(uint24) * max(uint16)) ** 2 < max(uint104)`
            // It returns 18 decimals as:
            // decimals(variableFeeControl * (volatilityAccumulated * binStep)**2 / 100) = 4 + (4 + 4) * 2 - 2 = 18
            unchecked {
                uint256 _prod = uint256(_fp.volatilityAccumulated) * _fp.binStep;
                variableFee = (_prod * _prod * _fp.variableFeeControl + 99) / 100;
            }
        }
    }

    /// @notice Return the amount of fees from an amount
    /// @dev Rounds amount up, follows `amount = amountWithFees - getFeeAmountFrom(fp, amountWithFees)`
    /// @param _fp The current fee parameter
    /// @param _amountWithFees The amount of token sent
    /// @return The fee amount from the amount sent
    function getFeeAmountFrom(FeeParameters memory _fp, uint256 _amountWithFees) internal pure returns (uint256) {
        return (_amountWithFees * getTotalFee(_fp) + Constants.PRECISION - 1) / (Constants.PRECISION);
    }

    /// @notice Return the fees to add to an amount
    /// @dev Rounds amount up, follows `amountWithFees = amount + getFeeAmount(fp, amount)`
    /// @param _fp The current fee parameter
    /// @param _amount The amount of token sent
    /// @return The fee amount to add to the amount
    function getFeeAmount(FeeParameters memory _fp, uint256 _amount) internal pure returns (uint256) {
        uint256 _fee = getTotalFee(_fp);
        uint256 _denominator = Constants.PRECISION - _fee;
        return (_amount * _fee + _denominator - 1) / _denominator;
    }

    /// @notice Return the fees added when an user adds liquidity and change the ratio in the active bin
    /// @dev Rounds amount up
    /// @param _fp The current fee parameter
    /// @param _amountWithFees The amount of token sent
    /// @return The fee amount
    function getFeeAmountForC(FeeParameters memory _fp, uint256 _amountWithFees) internal pure returns (uint256) {
        uint256 _fee = getTotalFee(_fp);
        uint256 _denominator = Constants.PRECISION * Constants.PRECISION;
        return (_amountWithFees * _fee * (_fee + Constants.PRECISION) + _denominator - 1) / _denominator;
    }

    /// @notice Return the fees distribution added to an amount
    /// @param _fp The current fee parameter
    /// @param _fees The fee amount
    /// @return fees The fee distribution
    function getFeeAmountDistribution(FeeParameters memory _fp, uint256 _fees)
        internal
        pure
        returns (FeesDistribution memory fees)
    {
        fees.total = _fees.safe128();
        // unsafe math is fine because total >= protocol
        unchecked {
            fees.protocol = uint128((_fees * _fp.protocolShare) / Constants.BASIS_POINT_MAX);
        }
    }

    /// @notice Return the total fee, i.e. baseFee + variableFee
    /// @param _fp The current fee parameter
    /// @return The total fee, with 18 decimals
    function getTotalFee(FeeParameters memory _fp) private pure returns (uint256) {
        unchecked {
            return getBaseFee(_fp) + getVariableFee(_fp);
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";
import "./BitMath.sol";
import "./Constants.sol";
import "./Math512Bits.sol";

/// @title Liquidity Book Math Helper Library
/// @author Trader Joe
/// @notice Helper contract used for power and log calculations
library Math128x128 {
    using Math512Bits for uint256;
    using BitMath for uint256;

    uint256 constant LOG_SCALE_OFFSET = 127;
    uint256 constant LOG_SCALE = 1 << LOG_SCALE_OFFSET;
    uint256 constant LOG_SCALE_SQUARED = LOG_SCALE * LOG_SCALE;

    /// @notice Calculates the binary logarithm of x.
    ///
    /// @dev Based on the iterative approximation algorithm.
    /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation
    ///
    /// Requirements:
    /// - x must be greater than zero.
    ///
    /// Caveats:
    /// - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation
    /// Also because x is converted to an unsigned 129.127-binary fixed-point number during the operation to optimize the multiplication
    ///
    /// @param x The unsigned 128.128-binary fixed-point number for which to calculate the binary logarithm.
    /// @return result The binary logarithm as a signed 128.128-binary fixed-point number.
    function log2(uint256 x) internal pure returns (int256 result) {
        // Convert x to a unsigned 129.127-binary fixed-point number to optimize the multiplication.
        // If we use an offset of 128 bits, y would need 129 bits and y**2 would would overflow and we would have to
        // use mulDiv, by reducing x to 129.127-binary fixed-point number we assert that y will use 128 bits, and we
        // can use the regular multiplication

        if (x == 1) return -128;
        if (x == 0) revert Math128x128__LogUnderflow();

        x >>= 1;

        unchecked {
            // This works because log2(x) = -log2(1/x).
            int256 sign;
            if (x >= LOG_SCALE) {
                sign = 1;
            } else {
                sign = -1;
                // Do the fixed-point inversion inline to save gas
                x = LOG_SCALE_SQUARED / x;
            }

            // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).
            uint256 n = (x >> LOG_SCALE_OFFSET).mostSignificantBit();

            // The integer part of the logarithm as a signed 129.127-binary fixed-point number. The operation can't overflow
            // because n is maximum 255, LOG_SCALE_OFFSET is 127 bits and sign is either 1 or -1.
            result = int256(n) << LOG_SCALE_OFFSET;

            // This is y = x * 2^(-n).
            uint256 y = x >> n;

            // If y = 1, the fractional part is zero.
            if (y != LOG_SCALE) {
                // Calculate the fractional part via the iterative approximation.
                // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster.
                for (int256 delta = int256(1 << (LOG_SCALE_OFFSET - 1)); delta > 0; delta >>= 1) {
                    y = (y * y) >> LOG_SCALE_OFFSET;

                    // Is y^2 > 2 and so in the range [2,4)?
                    if (y >= 1 << (LOG_SCALE_OFFSET + 1)) {
                        // Add the 2^(-m) factor to the logarithm.
                        result += delta;

                        // Corresponds to z/2 on Wikipedia.
                        y >>= 1;
                    }
                }
            }
            // Convert x back to unsigned 128.128-binary fixed-point number
            result = (result * sign) << 1;
        }
    }

    /// @notice Returns the value of x^y. It calculates `1 / x^abs(y)` if x is bigger than 2^128.
    /// At the end of the operations, we invert the result if needed.
    /// @param x The unsigned 128.128-binary fixed-point number for which to calculate the power
    /// @param y A relative number without any decimals, needs to be between ]2^20; 2^20[
    /// @return result The result of `x^y`
    function power(uint256 x, int256 y) internal pure returns (uint256 result) {
        bool invert;
        uint256 absY;

        if (y == 0) return Constants.SCALE;

        assembly {
            absY := y
            if slt(absY, 0) {
                absY := sub(0, absY)
                invert := iszero(invert)
            }
        }

        if (absY < 0x100000) {
            result = Constants.SCALE;
            assembly {
                let pow := x
                if gt(x, 0xffffffffffffffffffffffffffffffff) {
                    pow := div(not(0), pow)
                    invert := iszero(invert)
                }

                if and(absY, 0x1) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x2) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x4) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x8) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x10) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x20) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x40) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x80) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x100) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x200) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x400) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x800) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x1000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x2000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x4000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x8000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x10000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x20000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x40000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x80000) {
                    result := shr(128, mul(result, pow))
                }
            }
        }

        // revert if y is too big or if x^y underflowed
        if (result == 0) revert Math128x128__PowerUnderflow(x, y);

        return invert ? type(uint256).max / result : result;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";
import "./BitMath.sol";

/// @title Liquidity Book Math Helper Library
/// @author Trader Joe
/// @notice Helper contract used for full precision calculations
library Math512Bits {
    using BitMath for uint256;

    /// @notice Calculates floor(x*y÷denominator) with full precision
    /// The result will be rounded down
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    ///
    /// Requirements:
    /// - The denominator cannot be zero
    /// - The result must fit within uint256
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers
    ///
    /// @param x The multiplicand as an uint256
    /// @param y The multiplier as an uint256
    /// @param denominator The divisor as an uint256
    /// @return result The result as an uint256
    function mulDivRoundDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        (uint256 prod0, uint256 prod1) = _getMulProds(x, y);

        return _getEndOfDivRoundDown(x, y, denominator, prod0, prod1);
    }

    /// @notice Calculates x * y >> offset with full precision
    /// The result will be rounded down
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    ///
    /// Requirements:
    /// - The offset needs to be strictly lower than 256
    /// - The result must fit within uint256
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers
    ///
    /// @param x The multiplicand as an uint256
    /// @param y The multiplier as an uint256
    /// @param offset The offset as an uint256, can't be greater than 256
    /// @return result The result as an uint256
    function mulShiftRoundDown(
        uint256 x,
        uint256 y,
        uint256 offset
    ) internal pure returns (uint256 result) {
        if (offset > 255) revert Math512Bits__OffsetOverflows(offset);

        (uint256 prod0, uint256 prod1) = _getMulProds(x, y);

        if (prod0 != 0) result = prod0 >> offset;
        if (prod1 != 0) {
            // Make sure the result is less than 2^256.
            if (prod1 >= 1 << offset) revert Math512Bits__MulShiftOverflow(prod1, offset);

            unchecked {
                result += prod1 << (256 - offset);
            }
        }
    }

    /// @notice Calculates x * y >> offset with full precision
    /// The result will be rounded up
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    ///
    /// Requirements:
    /// - The offset needs to be strictly lower than 256
    /// - The result must fit within uint256
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers
    ///
    /// @param x The multiplicand as an uint256
    /// @param y The multiplier as an uint256
    /// @param offset The offset as an uint256, can't be greater than 256
    /// @return result The result as an uint256
    function mulShiftRoundUp(
        uint256 x,
        uint256 y,
        uint256 offset
    ) internal pure returns (uint256 result) {
        unchecked {
            result = mulShiftRoundDown(x, y, offset);
            if (mulmod(x, y, 1 << offset) != 0) result += 1;
        }
    }

    /// @notice Calculates x << offset / y with full precision
    /// The result will be rounded down
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    ///
    /// Requirements:
    /// - The offset needs to be strictly lower than 256
    /// - The result must fit within uint256
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers
    ///
    /// @param x The multiplicand as an uint256
    /// @param offset The number of bit to shift x as an uint256
    /// @param denominator The divisor as an uint256
    /// @return result The result as an uint256
    function shiftDivRoundDown(
        uint256 x,
        uint256 offset,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        if (offset > 255) revert Math512Bits__OffsetOverflows(offset);
        uint256 prod0;
        uint256 prod1;

        prod0 = x << offset; // Least significant 256 bits of the product
        unchecked {
            prod1 = x >> (256 - offset); // Most significant 256 bits of the product
        }

        return _getEndOfDivRoundDown(x, 1 << offset, denominator, prod0, prod1);
    }

    /// @notice Calculates x << offset / y with full precision
    /// The result will be rounded up
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    ///
    /// Requirements:
    /// - The offset needs to be strictly lower than 256
    /// - The result must fit within uint256
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers
    ///
    /// @param x The multiplicand as an uint256
    /// @param offset The number of bit to shift x as an uint256
    /// @param denominator The divisor as an uint256
    /// @return result The result as an uint256
    function shiftDivRoundUp(
        uint256 x,
        uint256 offset,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        result = shiftDivRoundDown(x, offset, denominator);
        unchecked {
            if (mulmod(x, 1 << offset, denominator) != 0) result += 1;
        }
    }

    /// @notice Helper function to return the result of `x * y` as 2 uint256
    /// @param x The multiplicand as an uint256
    /// @param y The multiplier as an uint256
    /// @return prod0 The least significant 256 bits of the product
    /// @return prod1 The most significant 256 bits of the product
    function _getMulProds(uint256 x, uint256 y) private pure returns (uint256 prod0, uint256 prod1) {
        // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
        // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
        // variables such that product = prod1 * 2^256 + prod0.
        assembly {
            let mm := mulmod(x, y, not(0))
            prod0 := mul(x, y)
            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
        }
    }

    /// @notice Helper function to return the result of `x * y / denominator` with full precision
    /// @param x The multiplicand as an uint256
    /// @param y The multiplier as an uint256
    /// @param denominator The divisor as an uint256
    /// @param prod0 The least significant 256 bits of the product
    /// @param prod1 The most significant 256 bits of the product
    /// @return result The result as an uint256
    function _getEndOfDivRoundDown(
        uint256 x,
        uint256 y,
        uint256 denominator,
        uint256 prod0,
        uint256 prod1
    ) private pure returns (uint256 result) {
        // Handle non-overflow cases, 256 by 256 division
        if (prod1 == 0) {
            unchecked {
                result = prod0 / denominator;
            }
        } else {
            // Make sure the result is less than 2^256. Also prevents denominator == 0
            if (prod1 >= denominator) revert Math512Bits__MulDivOverflow(prod1, denominator);

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1
            // See https://cs.stackexchange.com/q/138556/92363
            unchecked {
                // Does not overflow because the denominator cannot be zero at this stage in the function
                uint256 lpotdod = denominator & (~denominator + 1);
                assembly {
                    // Divide denominator by lpotdod.
                    denominator := div(denominator, lpotdod)

                    // Divide [prod1 prod0] by lpotdod.
                    prod0 := div(prod0, lpotdod)

                    // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one
                    lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
                }

                // Shift in bits from prod1 into prod0
                prod0 |= prod1 * lpotdod;

                // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                // four bits. That is, denominator * inv = 1 mod 2^4
                uint256 inverse = (3 * denominator) ^ 2;

                // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                // in modular arithmetic, doubling the correct bits in each step
                inverse *= 2 - denominator * inverse; // inverse mod 2^8
                inverse *= 2 - denominator * inverse; // inverse mod 2^16
                inverse *= 2 - denominator * inverse; // inverse mod 2^32
                inverse *= 2 - denominator * inverse; // inverse mod 2^64
                inverse *= 2 - denominator * inverse; // inverse mod 2^128
                inverse *= 2 - denominator * inverse; // inverse mod 2^256

                // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                // is no longer required.
                result = prod0 * inverse;
            }
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";
import "../interfaces/IPendingOwnable.sol";

/// @title Pending Ownable
/// @author Trader Joe
/// @notice 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. The ownership of this contract is transferred using the
/// push and pull pattern, the current owner set a `pendingOwner` using
/// {setPendingOwner} and that address can then call {becomeOwner} to become the
/// owner of that contract. The main logic and comments comes from OpenZeppelin's
/// Ownable contract.
///
/// By default, the owner account will be the one that deploys the contract. This
/// can later be changed with {setPendingOwner} and {becomeOwner}.
///
/// 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
contract PendingOwnable is IPendingOwnable {
    address private _owner;
    address private _pendingOwner;

    /// @notice Throws if called by any account other than the owner.
    modifier onlyOwner() {
        if (msg.sender != _owner) revert PendingOwnable__NotOwner();
        _;
    }

    /// @notice Throws if called by any account other than the pending owner.
    modifier onlyPendingOwner() {
        if (msg.sender != _pendingOwner || msg.sender == address(0)) revert PendingOwnable__NotPendingOwner();
        _;
    }

    /// @notice Initializes the contract setting the deployer as the initial owner
    constructor() {
        _transferOwnership(msg.sender);
    }

    /// @notice Returns the address of the current owner
    /// @return The address of the current owner
    function owner() public view override returns (address) {
        return _owner;
    }

    /// @notice Returns the address of the current pending owner
    /// @return The address of the current pending owner
    function pendingOwner() public view override returns (address) {
        return _pendingOwner;
    }

    /// @notice Sets the pending owner address. This address will be able to become
    /// the owner of this contract by calling {becomeOwner}
    function setPendingOwner(address pendingOwner_) public override onlyOwner {
        if (pendingOwner_ == address(0)) revert PendingOwnable__AddressZero();
        if (_pendingOwner != address(0)) revert PendingOwnable__PendingOwnerAlreadySet();
        _setPendingOwner(pendingOwner_);
    }

    /// @notice Revoke the pending owner address. This address will not be able to
    /// call {becomeOwner} to become the owner anymore.
    /// Can only be called by the owner
    function revokePendingOwner() public override onlyOwner {
        if (_pendingOwner == address(0)) revert PendingOwnable__NoPendingOwner();
        _setPendingOwner(address(0));
    }

    /// @notice Transfers the ownership to the new owner (`pendingOwner).
    /// Can only be called by the pending owner
    function becomeOwner() public override onlyPendingOwner {
        _transferOwnership(msg.sender);
    }

    /// @notice 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 override onlyOwner {
        _transferOwnership(address(0));
    }

    /// @notice Transfers ownership of the contract to a new account (`newOwner`).
    /// Internal function without access restriction.
    /// @param _newOwner The address of the new owner
    function _transferOwnership(address _newOwner) internal virtual {
        address _oldOwner = _owner;
        _owner = _newOwner;
        _pendingOwner = address(0);
        emit OwnershipTransferred(_oldOwner, _newOwner);
    }

    /// @notice Push the new owner, it needs to be pulled to be effective.
    /// Internal function without access restriction.
    /// @param pendingOwner_ The address of the new pending owner
    function _setPendingOwner(address pendingOwner_) internal virtual {
        _pendingOwner = pendingOwner_;
        emit PendingOwnerSet(pendingOwner_);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";

/// @title Liquidity Book Safe Cast Library
/// @author Trader Joe
/// @notice Helper contract used for converting uint values safely
library SafeCast {
    /// @notice Returns x on uint248 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint248
    function safe248(uint256 x) internal pure returns (uint248 y) {
        if ((y = uint248(x)) != x) revert SafeCast__Exceeds248Bits(x);
    }

    /// @notice Returns x on uint240 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint240
    function safe240(uint256 x) internal pure returns (uint240 y) {
        if ((y = uint240(x)) != x) revert SafeCast__Exceeds240Bits(x);
    }

    /// @notice Returns x on uint232 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint232
    function safe232(uint256 x) internal pure returns (uint232 y) {
        if ((y = uint232(x)) != x) revert SafeCast__Exceeds232Bits(x);
    }

    /// @notice Returns x on uint224 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint224
    function safe224(uint256 x) internal pure returns (uint224 y) {
        if ((y = uint224(x)) != x) revert SafeCast__Exceeds224Bits(x);
    }

    /// @notice Returns x on uint216 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint216
    function safe216(uint256 x) internal pure returns (uint216 y) {
        if ((y = uint216(x)) != x) revert SafeCast__Exceeds216Bits(x);
    }

    /// @notice Returns x on uint208 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint208
    function safe208(uint256 x) internal pure returns (uint208 y) {
        if ((y = uint208(x)) != x) revert SafeCast__Exceeds208Bits(x);
    }

    /// @notice Returns x on uint200 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint200
    function safe200(uint256 x) internal pure returns (uint200 y) {
        if ((y = uint200(x)) != x) revert SafeCast__Exceeds200Bits(x);
    }

    /// @notice Returns x on uint192 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint192
    function safe192(uint256 x) internal pure returns (uint192 y) {
        if ((y = uint192(x)) != x) revert SafeCast__Exceeds192Bits(x);
    }

    /// @notice Returns x on uint184 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint184
    function safe184(uint256 x) internal pure returns (uint184 y) {
        if ((y = uint184(x)) != x) revert SafeCast__Exceeds184Bits(x);
    }

    /// @notice Returns x on uint176 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint176
    function safe176(uint256 x) internal pure returns (uint176 y) {
        if ((y = uint176(x)) != x) revert SafeCast__Exceeds176Bits(x);
    }

    /// @notice Returns x on uint168 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint168
    function safe168(uint256 x) internal pure returns (uint168 y) {
        if ((y = uint168(x)) != x) revert SafeCast__Exceeds168Bits(x);
    }

    /// @notice Returns x on uint160 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint160
    function safe160(uint256 x) internal pure returns (uint160 y) {
        if ((y = uint160(x)) != x) revert SafeCast__Exceeds160Bits(x);
    }

    /// @notice Returns x on uint152 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint152
    function safe152(uint256 x) internal pure returns (uint152 y) {
        if ((y = uint152(x)) != x) revert SafeCast__Exceeds152Bits(x);
    }

    /// @notice Returns x on uint144 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint144
    function safe144(uint256 x) internal pure returns (uint144 y) {
        if ((y = uint144(x)) != x) revert SafeCast__Exceeds144Bits(x);
    }

    /// @notice Returns x on uint136 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint136
    function safe136(uint256 x) internal pure returns (uint136 y) {
        if ((y = uint136(x)) != x) revert SafeCast__Exceeds136Bits(x);
    }

    /// @notice Returns x on uint128 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint128
    function safe128(uint256 x) internal pure returns (uint128 y) {
        if ((y = uint128(x)) != x) revert SafeCast__Exceeds128Bits(x);
    }

    /// @notice Returns x on uint120 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint120
    function safe120(uint256 x) internal pure returns (uint120 y) {
        if ((y = uint120(x)) != x) revert SafeCast__Exceeds120Bits(x);
    }

    /// @notice Returns x on uint112 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint112
    function safe112(uint256 x) internal pure returns (uint112 y) {
        if ((y = uint112(x)) != x) revert SafeCast__Exceeds112Bits(x);
    }

    /// @notice Returns x on uint104 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint104
    function safe104(uint256 x) internal pure returns (uint104 y) {
        if ((y = uint104(x)) != x) revert SafeCast__Exceeds104Bits(x);
    }

    /// @notice Returns x on uint96 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint96
    function safe96(uint256 x) internal pure returns (uint96 y) {
        if ((y = uint96(x)) != x) revert SafeCast__Exceeds96Bits(x);
    }

    /// @notice Returns x on uint88 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint88
    function safe88(uint256 x) internal pure returns (uint88 y) {
        if ((y = uint88(x)) != x) revert SafeCast__Exceeds88Bits(x);
    }

    /// @notice Returns x on uint80 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint80
    function safe80(uint256 x) internal pure returns (uint80 y) {
        if ((y = uint80(x)) != x) revert SafeCast__Exceeds80Bits(x);
    }

    /// @notice Returns x on uint72 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint72
    function safe72(uint256 x) internal pure returns (uint72 y) {
        if ((y = uint72(x)) != x) revert SafeCast__Exceeds72Bits(x);
    }

    /// @notice Returns x on uint64 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint64
    function safe64(uint256 x) internal pure returns (uint64 y) {
        if ((y = uint64(x)) != x) revert SafeCast__Exceeds64Bits(x);
    }

    /// @notice Returns x on uint56 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint56
    function safe56(uint256 x) internal pure returns (uint56 y) {
        if ((y = uint56(x)) != x) revert SafeCast__Exceeds56Bits(x);
    }

    /// @notice Returns x on uint48 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint48
    function safe48(uint256 x) internal pure returns (uint48 y) {
        if ((y = uint48(x)) != x) revert SafeCast__Exceeds48Bits(x);
    }

    /// @notice Returns x on uint40 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint40
    function safe40(uint256 x) internal pure returns (uint40 y) {
        if ((y = uint40(x)) != x) revert SafeCast__Exceeds40Bits(x);
    }

    /// @notice Returns x on uint32 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint32
    function safe32(uint256 x) internal pure returns (uint32 y) {
        if ((y = uint32(x)) != x) revert SafeCast__Exceeds32Bits(x);
    }

    /// @notice Returns x on uint24 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint24
    function safe24(uint256 x) internal pure returns (uint24 y) {
        if ((y = uint24(x)) != x) revert SafeCast__Exceeds24Bits(x);
    }

    /// @notice Returns x on uint16 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint16
    function safe16(uint256 x) internal pure returns (uint16 y) {
        if ((y = uint16(x)) != x) revert SafeCast__Exceeds16Bits(x);
    }

    /// @notice Returns x on uint8 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint8
    function safe8(uint256 x) internal pure returns (uint8 y) {
        if ((y = uint8(x)) != x) revert SafeCast__Exceeds8Bits(x);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/// @title Liquidity Book Safe Math Helper Library
/// @author Trader Joe
/// @notice Helper contract used for calculating absolute value safely
library SafeMath {
    /// @notice absSub, can't underflow or overflow
    /// @param x The first value
    /// @param y The second value
    /// @return The result of abs(x - y)
    function absSub(uint256 x, uint256 y) internal pure returns (uint256) {
        unchecked {
            return x > y ? x - y : y - x;
        }
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_feeRecipient","type":"address"},{"internalType":"uint256","name":"_flashLoanFee","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"bp","type":"uint256"}],"name":"BinHelper__BinStepOverflows","type":"error"},{"inputs":[],"name":"BinHelper__IdOverflows","type":"error"},{"inputs":[],"name":"LBFactory__AddressZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBFactory__BinStepHasNoPreset","type":"error"},{"inputs":[{"internalType":"uint256","name":"lowerBound","type":"uint256"},{"internalType":"uint16","name":"binStep","type":"uint16"},{"internalType":"uint256","name":"higherBound","type":"uint256"}],"name":"LBFactory__BinStepRequirementsBreached","type":"error"},{"inputs":[{"internalType":"uint16","name":"filterPeriod","type":"uint16"},{"internalType":"uint16","name":"decayPeriod","type":"uint16"}],"name":"LBFactory__DecreasingPeriods","type":"error"},{"inputs":[],"name":"LBFactory__FactoryLockIsAlreadyInTheSameState","type":"error"},{"inputs":[{"internalType":"uint256","name":"fees","type":"uint256"},{"internalType":"uint256","name":"maxFees","type":"uint256"}],"name":"LBFactory__FeesAboveMax","type":"error"},{"inputs":[{"internalType":"uint256","name":"fees","type":"uint256"},{"internalType":"uint256","name":"maxFees","type":"uint256"}],"name":"LBFactory__FlashLoanFeeAboveMax","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"LBFactory__FunctionIsLockedForUsers","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"LBFactory__IdenticalAddresses","type":"error"},{"inputs":[],"name":"LBFactory__ImplementationNotSet","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","name":"_binStep","type":"uint256"}],"name":"LBFactory__LBPairAlreadyExists","type":"error"},{"inputs":[],"name":"LBFactory__LBPairIgnoredIsAlreadyInTheSameState","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBFactory__LBPairNotCreated","type":"error"},{"inputs":[{"internalType":"address","name":"LBPairImplementation","type":"address"}],"name":"LBFactory__LBPairSafetyCheckFailed","type":"error"},{"inputs":[{"internalType":"uint16","name":"protocolShare","type":"uint16"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"LBFactory__ProtocolShareOverflows","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"quoteAsset","type":"address"}],"name":"LBFactory__QuoteAssetAlreadyWhitelisted","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"quoteAsset","type":"address"}],"name":"LBFactory__QuoteAssetNotWhitelisted","type":"error"},{"inputs":[{"internalType":"uint16","name":"reductionFactor","type":"uint16"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"LBFactory__ReductionFactorOverflows","type":"error"},{"inputs":[{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"LBFactory__SameFeeRecipient","type":"error"},{"inputs":[{"internalType":"uint256","name":"flashLoanFee","type":"uint256"}],"name":"LBFactory__SameFlashLoanFee","type":"error"},{"inputs":[{"internalType":"address","name":"LBPairImplementation","type":"address"}],"name":"LBFactory__SameImplementation","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"int256","name":"y","type":"int256"}],"name":"Math128x128__PowerUnderflow","type":"error"},{"inputs":[],"name":"PendingOwnable__AddressZero","type":"error"},{"inputs":[],"name":"PendingOwnable__NoPendingOwner","type":"error"},{"inputs":[],"name":"PendingOwnable__NotOwner","type":"error"},{"inputs":[],"name":"PendingOwnable__NotPendingOwner","type":"error"},{"inputs":[],"name":"PendingOwnable__PendingOwnerAlreadySet","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"SafeCast__Exceeds16Bits","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"unlocked","type":"bool"}],"name":"FactoryLockedStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"contract ILBPair","name":"LBPair","type":"address"},{"indexed":false,"internalType":"uint256","name":"binStep","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseFactor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"filterPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"decayPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reductionFactor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"variableFeeControl","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxVolatilityAccumulated","type":"uint256"}],"name":"FeeParametersSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"newRecipient","type":"address"}],"name":"FeeRecipientSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFlashLoanFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFlashLoanFee","type":"uint256"}],"name":"FlashLoanFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"tokenX","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"tokenY","type":"address"},{"indexed":true,"internalType":"uint256","name":"binStep","type":"uint256"},{"indexed":false,"internalType":"contract ILBPair","name":"LBPair","type":"address"},{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"}],"name":"LBPairCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ILBPair","name":"LBPair","type":"address"},{"indexed":false,"internalType":"bool","name":"ignored","type":"bool"}],"name":"LBPairIgnoredStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldLBPairImplementation","type":"address"},{"indexed":false,"internalType":"address","name":"LBPairImplementation","type":"address"}],"name":"LBPairImplementationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"PendingOwnerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"PresetRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"binStep","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseFactor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"filterPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"decayPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reductionFactor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"variableFeeControl","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxVolatilityAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sampleLifetime","type":"uint256"}],"name":"PresetSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"quoteAsset","type":"address"}],"name":"QuoteAssetAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"quoteAsset","type":"address"}],"name":"QuoteAssetRemoved","type":"event"},{"inputs":[],"name":"LBPairImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BIN_STEP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PROTOCOL_SHARE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_BIN_STEP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_quoteAsset","type":"address"}],"name":"addQuoteAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allLBPairs","outputs":[{"internalType":"contract ILBPair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"becomeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenX","type":"address"},{"internalType":"contract IERC20","name":"_tokenY","type":"address"},{"internalType":"uint24","name":"_activeId","type":"uint24"},{"internalType":"uint16","name":"_binStep","type":"uint16"}],"name":"createLBPair","outputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"creationUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flashLoanFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"}],"name":"forceDecay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllBinSteps","outputs":[{"internalType":"uint256[]","name":"presetsBinStep","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenX","type":"address"},{"internalType":"contract IERC20","name":"_tokenY","type":"address"}],"name":"getAllLBPairs","outputs":[{"components":[{"internalType":"uint16","name":"binStep","type":"uint16"},{"internalType":"contract ILBPair","name":"LBPair","type":"address"},{"internalType":"bool","name":"createdByOwner","type":"bool"},{"internalType":"bool","name":"ignoredForRouting","type":"bool"}],"internalType":"struct ILBFactory.LBPairInformation[]","name":"LBPairsAvailable","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenA","type":"address"},{"internalType":"contract IERC20","name":"_tokenB","type":"address"},{"internalType":"uint256","name":"_binStep","type":"uint256"}],"name":"getLBPairInformation","outputs":[{"components":[{"internalType":"uint16","name":"binStep","type":"uint16"},{"internalType":"contract ILBPair","name":"LBPair","type":"address"},{"internalType":"bool","name":"createdByOwner","type":"bool"},{"internalType":"bool","name":"ignoredForRouting","type":"bool"}],"internalType":"struct ILBFactory.LBPairInformation","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumberOfLBPairs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumberOfQuoteAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_binStep","type":"uint16"}],"name":"getPreset","outputs":[{"internalType":"uint256","name":"baseFactor","type":"uint256"},{"internalType":"uint256","name":"filterPeriod","type":"uint256"},{"internalType":"uint256","name":"decayPeriod","type":"uint256"},{"internalType":"uint256","name":"reductionFactor","type":"uint256"},{"internalType":"uint256","name":"variableFeeControl","type":"uint256"},{"internalType":"uint256","name":"protocolShare","type":"uint256"},{"internalType":"uint256","name":"maxVolatilityAccumulated","type":"uint256"},{"internalType":"uint256","name":"sampleLifetime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getQuoteAsset","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"}],"name":"isQuoteAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_binStep","type":"uint16"}],"name":"removePreset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_quoteAsset","type":"address"}],"name":"removeQuoteAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokePendingOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_locked","type":"bool"}],"name":"setFactoryLockedState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenX","type":"address"},{"internalType":"contract IERC20","name":"_tokenY","type":"address"},{"internalType":"uint16","name":"_binStep","type":"uint16"},{"internalType":"uint16","name":"_baseFactor","type":"uint16"},{"internalType":"uint16","name":"_filterPeriod","type":"uint16"},{"internalType":"uint16","name":"_decayPeriod","type":"uint16"},{"internalType":"uint16","name":"_reductionFactor","type":"uint16"},{"internalType":"uint24","name":"_variableFeeControl","type":"uint24"},{"internalType":"uint16","name":"_protocolShare","type":"uint16"},{"internalType":"uint24","name":"_maxVolatilityAccumulated","type":"uint24"}],"name":"setFeesParametersOnPair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_flashLoanFee","type":"uint256"}],"name":"setFlashLoanFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenX","type":"address"},{"internalType":"contract IERC20","name":"_tokenY","type":"address"},{"internalType":"uint256","name":"_binStep","type":"uint256"},{"internalType":"bool","name":"_ignored","type":"bool"}],"name":"setLBPairIgnored","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_LBPairImplementation","type":"address"}],"name":"setLBPairImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner_","type":"address"}],"name":"setPendingOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_binStep","type":"uint16"},{"internalType":"uint16","name":"_baseFactor","type":"uint16"},{"internalType":"uint16","name":"_filterPeriod","type":"uint16"},{"internalType":"uint16","name":"_decayPeriod","type":"uint16"},{"internalType":"uint16","name":"_reductionFactor","type":"uint16"},{"internalType":"uint24","name":"_variableFeeControl","type":"uint24"},{"internalType":"uint16","name":"_protocolShare","type":"uint16"},{"internalType":"uint24","name":"_maxVolatilityAccumulated","type":"uint24"},{"internalType":"uint16","name":"_sampleLifetime","type":"uint16"}],"name":"setPreset","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b5060405162002c9038038062002c908339810160408190526200003491620001f0565b6200003f33620000d1565b67016345785d8a00008111156200007f57604051635e8988c160e01b81526004810182905267016345785d8a000060248201526044015b60405180910390fd5b6200008a826200012b565b60048190556040805160008152602081018390527f5c34e91c94c78b662a45d0bd4a25a4e32c584c54a45a76e4a4d43be27ba40e50910160405180910390a150506200022c565b600080546001600160a01b038381166001600160a01b031980841682178555600180549091169055604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381166200015357604051632573cfb960e21b815260040160405180910390fd5b6003546001600160a01b039081169082168114156200019157604051634fcea97160e01b81526001600160a01b038316600482015260240162000076565b600380546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f15d80a013f22151bc7246e3bc132e12828cde19de98870475e3fa70840152721910160405180910390a15050565b600080604083850312156200020457600080fd5b82516001600160a01b03811681146200021c57600080fd5b6020939093015192949293505050565b612a54806200023c6000396000f3fe608060405234801561001057600080fd5b50600436106102415760003560e01c8063704037bd11610145578063bc063e1a116100bd578063e30c39781161008c578063e92d0d5d11610071578063e92d0d5d146104dd578063f89a4cd5146104f0578063f9dca9891461050357600080fd5b8063e30c3978146104b9578063e74b981b146104ca57600080fd5b8063bc063e1a14610471578063c42069ec14610480578063ddbfd94114610493578063e203a31f146104a657600080fd5b806380c5061e11610114578063935ea51b116100f9578063935ea51b14610407578063a931208f14610455578063b03847811461045e57600080fd5b806380c5061e146103ee5780638da5cb5b146103f657600080fd5b8063704037bd146103ab578063715018a6146103cb57806372e47b8c146103d35780637df880e3146103e657600080fd5b80634847cdc8116101d85780635b35875c116101a7578063659ac74b1161018c578063659ac74b146103705780636622e0d71461038357806367ab8a4e146103a357600080fd5b80635b35875c146103475780635c779d6d1461035c57600080fd5b80634847cdc8146103105780634e937c3a14610319578063509ceb90146103215780635a4409231461033457600080fd5b806322f3fe141161021457806322f3fe141461029c57806327721842146102af5780633c78a941146102d257806346904840146102e557600080fd5b8063093ff769146102465780630af97c9a1461025b57806310e9ec4a1461026e578063200aa7e314610289575b600080fd5b610259610254366004612524565b61050b565b005b6102596102693660046125e2565b610693565b610276606481565b6040519081526020015b60405180910390f35b61025961029736600461269a565b6107da565b6102596102aa3660046126eb565b61097e565b6102c26102bd366004612706565b610a4c565b6040519015158152602001610280565b6102596102e0366004612706565b610a5f565b6003546102f8906001600160a01b031681565b6040516001600160a01b039091168152602001610280565b61027660045481565b600554610276565b6002546102f8906001600160a01b031681565b610259610342366004612706565b610ae0565b61034f610b75565b6040516102809190612723565b6003546102c290600160a01b900460ff1681565b6102f861037e366004612767565b610c28565b6103966103913660046127b4565b61122e565b60405161028091906127ed565b6102596113fd565b6103be6103b9366004612861565b61145d565b60405161028091906128a2565b610259611494565b6102f86103e13660046128de565b6114c9565b610276600181565b6102766114f3565b6000546001600160a01b03166102f8565b61041a6104153660046128f7565b611504565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e082015261010001610280565b6102766109c481565b61025961046c366004612706565b611604565b61027667016345785d8a000081565b61025961048e366004612706565b611769565b6102596104a1366004612706565b6117f1565b6102596104b43660046128f7565b611886565b6001546001600160a01b03166102f8565b6102596104d8366004612706565b611957565b6102596104eb3660046128de565b61198b565b6102f86104fe3660046128de565b611a52565b610259611a5f565b6000546001600160a01b0316331461053657604051639f216c1360e01b815260040160405180910390fd5b60006105478b8b8b61ffff16611a9e565b6020015190506001600160a01b0381166105965760405163b65ee95360e01b81526001600160a01b03808d1660048301528b16602482015261ffff8a1660448201526064015b60405180910390fd5b60006105a88a8a8a8a8a8a8a8a611b48565b6040516354b5fc8760e01b8152600481018290529091506001600160a01b038316906354b5fc8790602401600060405180830381600087803b1580156105ed57600080fd5b505af1158015610601573d6000803e3d6000fd5b50506040805161ffff8e811682528d811660208301528c8116828401528b811660608301528a8116608083015262ffffff8a811660a084015290891660c0830152871660e082015290516001600160a01b03861693503392507f63a7af39b7b68b9c3f2dfe93e5f32d9faecb4c6c98733bb608f757e62f816c0d918190036101000190a3505050505050505050505050565b6000546001600160a01b031633146106be57604051639f216c1360e01b815260040160405180910390fd5b60006106d08a8a8a8a8a8a8a8a611b48565b61ffff8b16600081815260086020526040902060f085901b7fffff0000000000000000000000000000000000000000000000000000000000001671ffffffffffffffffffffffffffffffffffff84161790819055600754929350919081901c60011661075557600161ffff8d161b1761074d81600160f81b612928565b600781905590505b6040805161ffff8d811682528c811660208301528b8116828401528a8116606083015262ffffff8a8116608084015289821660a0840152881660c083015286811660e08301529151918e16917f2f6cfdcc0e02e7355350f527dd3b5a957787b96f231165e48a3fdf90332a40cb918190036101000190a2505050505050505050505050565b6000546001600160a01b0316331461080557604051639f216c1360e01b815260040160405180910390fd5b6000806108128686611dbc565b6001600160a01b038083166000908152600660209081526040808320848616845282528083208a84528252918290208251608081018452905461ffff8116825262010000810490941691810182905260ff600160b01b85048116151593820193909352600160b81b90930490911615156060830152929450909250906108ab57604051632573cfb960e21b815260040160405180910390fd5b8315158160600151151514156108d357604051626ee66560e11b815260040160405180910390fd5b6001600160a01b038084166000908152600660209081526040808320868516845282528083208984528252918290208054881515600160b81b027fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff90911617905583015190519116907f44cf35361c9ff3c8c1397ec6410d5495cc481feaef35c9af11da1a637107de4f9061096d90871515815260200190565b60405180910390a250505050505050565b6000546001600160a01b031633146109a957604051639f216c1360e01b815260040160405180910390fd5b60035460ff600160a01b909104161515811515146109da576040516302dbbca560e21b815260040160405180910390fd5b60038054600160a01b8315027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9091161790556040517fcdee7bf87b7a743b4cbe1d2d534c5248621b76f58460337e7fda92d5d23f412490610a4190831515815260200190565b60405180910390a150565b6000610a59600983611de5565b92915050565b6000546001600160a01b03163314610a8a57604051639f216c1360e01b815260040160405180910390fd5b806001600160a01b031663d3b9fbe46040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610ac557600080fd5b505af1158015610ad9573d6000803e3d6000fd5b5050505050565b6000546001600160a01b03163314610b0b57604051639f216c1360e01b815260040160405180910390fd5b610b16600982611e0a565b610b3e576040516303ce0ad960e01b81526001600160a01b038216600482015260240161058d565b6040516001600160a01b038216907f84cc2115995684dcb0cd3d3a9565e3d32f075de81db70c8dc3a719b2a47af67e90600090a250565b60075460609060f881901c8015610c23578067ffffffffffffffff811115610b9f57610b9f612940565b604051908082528060200260200182016040528015610bc8578160200160208202803683370190505b509250600060015b60648111610c205783811c60011660011415610c185780858381518110610bf957610bf9612956565b60200260200101818152505082826001019250821415610c1857610c20565b600101610bd0565b50505b505090565b600080610c3d6000546001600160a01b031690565b600354909150600160a01b900460ff16158015610c635750336001600160a01b03821614155b15610c8257604051627487d360e71b815233600482015260240161058d565b6002546001600160a01b031680610cac576040516328b4fcf960e21b815260040160405180910390fd5b610cb7600987611de5565b610cdf57604051638e888ef360e01b81526001600160a01b038716600482015260240161058d565b856001600160a01b0316876001600160a01b03161415610d1d57604051632f9b185360e01b81526001600160a01b038816600482015260240161058d565b610d308562ffffff168561ffff16611e1f565b50600080610d3e8989611dbc565b90925090506001600160a01b038216610d6a57604051632573cfb960e21b815260040160405180910390fd5b6001600160a01b0382811660009081526006602090815260408083208585168452825280832061ffff8b1684529091529020546201000090041615610ddf5760405163cb27a43560e01b81526001600160a01b03808b1660048301528916602482015261ffff8716604482015260640161058d565b61ffff861660009081526008602052604090205480610e1757604051637d9160bf60e11b815261ffff8816600482015260240161058d565b604080516001600160a01b038581166020808401919091529085168284015261ffff8a16606080840191909152835180840390910181526080909201909252805191012071ffffffffffffffffffffffffffffffffffff82169160f01c90610e7f8682611e5f565b60405163d32db43760e01b81526001600160a01b038e811660048301528d8116602483015262ffffff8d16604483015261ffff85166064830152608482018690529199509089169063d32db4379060a401600060405180830381600087803b158015610eea57600080fd5b505af1158015610efe573d6000803e3d6000fd5b5050505060405180608001604052808a61ffff168152602001896001600160a01b03168152602001886001600160a01b0316336001600160a01b031614151581526020016000151581525060066000876001600160a01b03166001600160a01b031681526020019081526020016000206000866001600160a01b03166001600160a01b0316815260200190815260200160002060008b61ffff16815260200190815260200160002060008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160000160166101000a81548160ff02191690831515021790555060608201518160000160176101000a81548160ff0219169083151502179055509050506005889080600181540180825580915050600190039060005260206000200160009091909190916101000a8154816001600160a01b0302191690836001600160a01b031602179055506000600b6000876001600160a01b03166001600160a01b031681526020019081526020016000206000866001600160a01b03166001600160a01b031681526020019081526020016000205490508961ffff166001901b8160001c1760001b90508060001c600160f81b6110f59190612928565b6001600160a01b038088166000908152600b602090815260408083208a8516845290915290209190915560055461ffff8c1692508d8216918f16907f2c8d104b27c6b7f4492017a6f5cf3803043688934ebcaa6a03540beeaf976aff908c906111609060019061296c565b604080516001600160a01b03909316835260208301919091520160405180910390a46040805161ffff808c168252601086901c811660208381019190915286901c811682840152603086901c8116606083015285831c8116608083015262ffffff605087901c811660a0840152606887901c90911660c0830152607886901c1660e082015290516001600160a01b038a169133917f63a7af39b7b68b9c3f2dfe93e5f32d9faecb4c6c98733bb608f757e62f816c0d918190036101000190a350505050505050949350505050565b606060008061123d8585611dbc565b6001600160a01b038281166000908152600b6020908152604080832093851683529290522054919350915060f881901c80156113f3578067ffffffffffffffff81111561128c5761128c612940565b6040519080825280602002602001820160405280156112de57816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816112aa5790505b509450600060015b606481116113f05783811c600116600114156113e8576001600160a01b03808716600090815260066020908152604080832089851684528252808320858452825291829020825160808082018552915461ffff811682526201000081049095169281019290925260ff600160b01b85048116151583850152600160b81b909404909316151560608201528151928301909152908061138384611f16565b61ffff16815260200182602001516001600160a01b03168152602001826040015115158152602001826060015115158152508884815181106113c7576113c7612956565b6020026020010181905250838360010193508314156113e657506113f0565b505b6001016112e6565b50505b5050505092915050565b6000546001600160a01b0316331461142857604051639f216c1360e01b815260040160405180910390fd5b6001546001600160a01b03166114515760405163ecfad6bf60e01b815260040160405180910390fd5b61145b6000611f43565b565b60408051608081018252600080825260208201819052918101829052606081019190915261148c848484611a9e565b949350505050565b6000546001600160a01b031633146114bf57604051639f216c1360e01b815260040160405180910390fd5b61145b6000611f8d565b600581815481106114d957600080fd5b6000918252602090912001546001600160a01b0316905081565b60006114ff6009611fe7565b905090565b61ffff811660009081526008602052604081205481908190819081908190819081908061154a57604051637d9160bf60e11b815261ffff8b16600482015260240161058d565b600061ffff82168b61ffff161461156057600080fd5b61157a61ffff611571601084612928565b925083831c1690565b995061158d61ffff611571601084612928565b98506115a061ffff611571601084612928565b97506115b361ffff611571601084612928565b96506115c762ffffff611571601084612928565b95506115da61ffff611571601884612928565b94506115ee62ffffff611571601084612928565b935060f082901c92505050919395975091939597565b6000546001600160a01b0316331461162f57604051639f216c1360e01b815260040160405180910390fd5b306001600160a01b0316816001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015611677573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169b9190612983565b6001600160a01b0316146116cd57604051630a3e70af60e11b81526001600160a01b038216600482015260240161058d565b6002546001600160a01b0390811690821681141561170957604051630ded3b9560e31b81526001600160a01b038316600482015260240161058d565b600280546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f900d0e3d359f50e4f923ecdc06b401e07dbb9f485e17b07bcfc91a13000b277e91015b60405180910390a15050565b6000546001600160a01b0316331461179457604051639f216c1360e01b815260040160405180910390fd5b6001600160a01b0381166117bb576040516391f3851560e01b815260040160405180910390fd5b6001546001600160a01b0316156117e55760405163716b1fbf60e01b815260040160405180910390fd5b6117ee81611f43565b50565b6000546001600160a01b0316331461181c57604051639f216c1360e01b815260040160405180910390fd5b611827600982611ff1565b61184f57604051638e888ef360e01b81526001600160a01b038216600482015260240161058d565b6040516001600160a01b038216907f0b767739217755d8af5a2ba75b181a19fa1750f8bb701f09311cb19a90140cb390600090a250565b6000546001600160a01b031633146118b157604051639f216c1360e01b815260040160405180910390fd5b61ffff81166000908152600860205260409020546118e857604051637d9160bf60e11b815261ffff8216600482015260240161058d565b6007546118fe600161ffff84161b60001961296c565b1661190d600160f81b8261296c565b600781905561ffff83166000818152600860205260408082208290555192935090917fdd86b848bb56ff540caa68683fa467d0e7eb5f8b2d44e4ee435742eeeae9be139190a25050565b6000546001600160a01b0316331461198257604051639f216c1360e01b815260040160405180910390fd5b6117ee81612006565b6000546001600160a01b031633146119b657604051639f216c1360e01b815260040160405180910390fd5b600454818114156119dd57604051631baa31e960e21b81526004810183905260240161058d565b67016345785d8a0000821115611a1757604051635e8988c160e01b81526004810183905267016345785d8a0000602482015260440161058d565b600482905560408051828152602081018490527f5c34e91c94c78b662a45d0bd4a25a4e32c584c54a45a76e4a4d43be27ba40e50910161175d565b6000610a596009836120c1565b6001546001600160a01b031633141580611a77575033155b15611a9557604051633982680960e11b815260040160405180910390fd5b61145b33611f8d565b604080516080810182526000808252602082018190529181018290526060810191909152611acc8484611dbc565b6001600160a01b03918216600090815260066020908152604080832093851683529281528282209582529485528190208151608081018352905461ffff811682526201000081049093169481019490945260ff600160b01b83048116151591850191909152600160b81b90910416151560608301525092915050565b600060018961ffff161080611b61575060648961ffff16115b15611b9357604051634f95635f60e11b81526001600482015261ffff8a1660248201526064604482018190520161058d565b8561ffff168761ffff1610611bc95760405163744d432160e11b815261ffff80891660048301528716602482015260440161058d565b6127108561ffff161115611bfe5760405163632afa6960e11b815261ffff86166004820152612710602482015260440161058d565b6109c48361ffff161115611c3357604051630d0ada2960e41b815261ffff841660048201526109c4602482015260440161058d565b6000611c4661ffff808c16908b166129a0565b611c55906402540be4006129a0565b90506000611c6c61ffff8c1662ffffff86166129a0565b90506000606462ffffff8816611c8284806129a0565b611c8c91906129a0565b611c9691906129bf565b905067016345785d8a0000611cab8285612928565b1115611ce657611cbb8184612928565b604051633fb210a760e21b8152600481019190915267016345785d8a0000602482015260440161058d565b50506040805171ffffff000000000000000000000000000000607886901b1660208201527fffff00000000000000000000000000000000000000000000000000000000000060f087811b821660318401527fffffff000000000000000000000000000000000000000000000000000000000060e88a901b16603384015289811b821660368401528a811b821660388401528b811b8216603a8401528c811b8216603c8401528d901b16603e820152019050604051602081830303815290604052611daf906129e1565b9998505050505050505050565b600080826001600160a01b0316846001600160a01b03161115611ddd579192915b509192909150565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b6000611e03836001600160a01b0384166120cd565b600062ffffff831115611e455760405163163d8bab60e21b815260040160405180910390fd5b627fffff19830161148c81611e598561211c565b90612162565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528360601b60148201527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006028820152826037826000f59150506001600160a01b038116610a595760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c6564000000000000000000604482015260640161058d565b8061ffff81168114611f3e5760405163506fbff560e01b81526004810183905260240161058d565b919050565b600180546001600160a01b0319166001600160a01b0383169081179091556040517f68f49b346b94582a8b5f9d10e3fe3365318fe8f191ff8dce7c59c6cad06b02f590600090a250565b600080546001600160a01b038381166001600160a01b031980841682178555600180549091169055604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610a59825490565b6000611e03836001600160a01b0384166123cd565b6001600160a01b03811661202d57604051632573cfb960e21b815260040160405180910390fd5b6003546001600160a01b0390811690821681141561206957604051634fcea97160e01b81526001600160a01b038316600482015260240161058d565b600380546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f15d80a013f22151bc7246e3bc132e12828cde19de98870475e3fa70840152721910161175d565b6000611e0383836124c0565b600081815260018301602052604081205461211457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610a59565b506000610a59565b600081158061212c575061271082115b1561214d576040516374da1e1160e11b81526004810183905260240161058d565b612710608083901b04600160801b0192915050565b600080808361217a5750600160801b9150610a599050565b5082600081121561218c579015906000035b6210000081101561238557600160801b9250846fffffffffffffffffffffffffffffffff8111156121bf57911591600019045b60018216156121d05792830260801c925b800260801c60028216156121e65792830260801c925b800260801c60048216156121fc5792830260801c925b800260801c60088216156122125792830260801c925b800260801c60108216156122285792830260801c925b800260801c602082161561223e5792830260801c925b800260801c60408216156122545792830260801c925b8002608090811c9082161561226b5792830260801c925b800260801c6101008216156122825792830260801c925b800260801c6102008216156122995792830260801c925b800260801c6104008216156122b05792830260801c925b800260801c6108008216156122c75792830260801c925b800260801c6110008216156122de5792830260801c925b800260801c6120008216156122f55792830260801c925b800260801c61400082161561230c5792830260801c925b800260801c6180008216156123235792830260801c925b800260801c6201000082161561233b5792830260801c925b800260801c620200008216156123535792830260801c925b800260801c6204000082161561236b5792830260801c925b800260801c620800008216156123835792830260801c925b505b826123ad57604051630e9c7d6160e31b8152600481018690526024810185905260440161058d565b816123b857826123c4565b6123c4836000196129bf565b95945050505050565b600081815260018301602052604081205480156124b65760006123f160018361296c565b85549091506000906124059060019061296c565b905081811461246a57600086600001828154811061242557612425612956565b906000526020600020015490508087600001848154811061244857612448612956565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061247b5761247b612a08565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610a59565b6000915050610a59565b60008260000182815481106124d7576124d7612956565b9060005260206000200154905092915050565b6001600160a01b03811681146117ee57600080fd5b803561ffff81168114611f3e57600080fd5b803562ffffff81168114611f3e57600080fd5b6000806000806000806000806000806101408b8d03121561254457600080fd5b8a3561254f816124ea565b995060208b013561255f816124ea565b985061256d60408c016124ff565b975061257b60608c016124ff565b965061258960808c016124ff565b955061259760a08c016124ff565b94506125a560c08c016124ff565b93506125b360e08c01612511565b92506125c26101008c016124ff565b91506125d16101208c01612511565b90509295989b9194979a5092959850565b60008060008060008060008060006101208a8c03121561260157600080fd5b61260a8a6124ff565b985061261860208b016124ff565b975061262660408b016124ff565b965061263460608b016124ff565b955061264260808b016124ff565b945061265060a08b01612511565b935061265e60c08b016124ff565b925061266c60e08b01612511565b915061267b6101008b016124ff565b90509295985092959850929598565b80358015158114611f3e57600080fd5b600080600080608085870312156126b057600080fd5b84356126bb816124ea565b935060208501356126cb816124ea565b9250604085013591506126e06060860161268a565b905092959194509250565b6000602082840312156126fd57600080fd5b611e038261268a565b60006020828403121561271857600080fd5b8135611e03816124ea565b6020808252825182820181905260009190848201906040850190845b8181101561275b5783518352928401929184019160010161273f565b50909695505050505050565b6000806000806080858703121561277d57600080fd5b8435612788816124ea565b93506020850135612798816124ea565b92506127a660408601612511565b91506126e0606086016124ff565b600080604083850312156127c757600080fd5b82356127d2816124ea565b915060208301356127e2816124ea565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561275b5761284e83855161ffff81511682526001600160a01b0360208201511660208301526040810151151560408301526060810151151560608301525050565b9284019260809290920191600101612809565b60008060006060848603121561287657600080fd5b8335612881816124ea565b92506020840135612891816124ea565b929592945050506040919091013590565b815161ffff1681526020808301516001600160a01b03169082015260408083015115159082015260608083015115159082015260808101610a59565b6000602082840312156128f057600080fd5b5035919050565b60006020828403121561290957600080fd5b611e03826124ff565b634e487b7160e01b600052601160045260246000fd5b6000821982111561293b5761293b612912565b500190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008282101561297e5761297e612912565b500390565b60006020828403121561299557600080fd5b8151611e03816124ea565b60008160001904831182151516156129ba576129ba612912565b500290565b6000826129dc57634e487b7160e01b600052601260045260246000fd5b500490565b80516020808301519190811015612a02576000198160200360031b1b821691505b50919050565b634e487b7160e01b600052603160045260246000fdfea26469706673582212203b9f852cba9b69a7ead4adbbe5d3e43b7890dce2e48797cee6fa9fbfe22e2e6f64736f6c634300080a00330000000000000000000000001119fbb02f38764cd90f2d9fb35fedcd8378ac2a0000000000000000000000000000000000000000000000000000048c27395000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102415760003560e01c8063704037bd11610145578063bc063e1a116100bd578063e30c39781161008c578063e92d0d5d11610071578063e92d0d5d146104dd578063f89a4cd5146104f0578063f9dca9891461050357600080fd5b8063e30c3978146104b9578063e74b981b146104ca57600080fd5b8063bc063e1a14610471578063c42069ec14610480578063ddbfd94114610493578063e203a31f146104a657600080fd5b806380c5061e11610114578063935ea51b116100f9578063935ea51b14610407578063a931208f14610455578063b03847811461045e57600080fd5b806380c5061e146103ee5780638da5cb5b146103f657600080fd5b8063704037bd146103ab578063715018a6146103cb57806372e47b8c146103d35780637df880e3146103e657600080fd5b80634847cdc8116101d85780635b35875c116101a7578063659ac74b1161018c578063659ac74b146103705780636622e0d71461038357806367ab8a4e146103a357600080fd5b80635b35875c146103475780635c779d6d1461035c57600080fd5b80634847cdc8146103105780634e937c3a14610319578063509ceb90146103215780635a4409231461033457600080fd5b806322f3fe141161021457806322f3fe141461029c57806327721842146102af5780633c78a941146102d257806346904840146102e557600080fd5b8063093ff769146102465780630af97c9a1461025b57806310e9ec4a1461026e578063200aa7e314610289575b600080fd5b610259610254366004612524565b61050b565b005b6102596102693660046125e2565b610693565b610276606481565b6040519081526020015b60405180910390f35b61025961029736600461269a565b6107da565b6102596102aa3660046126eb565b61097e565b6102c26102bd366004612706565b610a4c565b6040519015158152602001610280565b6102596102e0366004612706565b610a5f565b6003546102f8906001600160a01b031681565b6040516001600160a01b039091168152602001610280565b61027660045481565b600554610276565b6002546102f8906001600160a01b031681565b610259610342366004612706565b610ae0565b61034f610b75565b6040516102809190612723565b6003546102c290600160a01b900460ff1681565b6102f861037e366004612767565b610c28565b6103966103913660046127b4565b61122e565b60405161028091906127ed565b6102596113fd565b6103be6103b9366004612861565b61145d565b60405161028091906128a2565b610259611494565b6102f86103e13660046128de565b6114c9565b610276600181565b6102766114f3565b6000546001600160a01b03166102f8565b61041a6104153660046128f7565b611504565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e082015261010001610280565b6102766109c481565b61025961046c366004612706565b611604565b61027667016345785d8a000081565b61025961048e366004612706565b611769565b6102596104a1366004612706565b6117f1565b6102596104b43660046128f7565b611886565b6001546001600160a01b03166102f8565b6102596104d8366004612706565b611957565b6102596104eb3660046128de565b61198b565b6102f86104fe3660046128de565b611a52565b610259611a5f565b6000546001600160a01b0316331461053657604051639f216c1360e01b815260040160405180910390fd5b60006105478b8b8b61ffff16611a9e565b6020015190506001600160a01b0381166105965760405163b65ee95360e01b81526001600160a01b03808d1660048301528b16602482015261ffff8a1660448201526064015b60405180910390fd5b60006105a88a8a8a8a8a8a8a8a611b48565b6040516354b5fc8760e01b8152600481018290529091506001600160a01b038316906354b5fc8790602401600060405180830381600087803b1580156105ed57600080fd5b505af1158015610601573d6000803e3d6000fd5b50506040805161ffff8e811682528d811660208301528c8116828401528b811660608301528a8116608083015262ffffff8a811660a084015290891660c0830152871660e082015290516001600160a01b03861693503392507f63a7af39b7b68b9c3f2dfe93e5f32d9faecb4c6c98733bb608f757e62f816c0d918190036101000190a3505050505050505050505050565b6000546001600160a01b031633146106be57604051639f216c1360e01b815260040160405180910390fd5b60006106d08a8a8a8a8a8a8a8a611b48565b61ffff8b16600081815260086020526040902060f085901b7fffff0000000000000000000000000000000000000000000000000000000000001671ffffffffffffffffffffffffffffffffffff84161790819055600754929350919081901c60011661075557600161ffff8d161b1761074d81600160f81b612928565b600781905590505b6040805161ffff8d811682528c811660208301528b8116828401528a8116606083015262ffffff8a8116608084015289821660a0840152881660c083015286811660e08301529151918e16917f2f6cfdcc0e02e7355350f527dd3b5a957787b96f231165e48a3fdf90332a40cb918190036101000190a2505050505050505050505050565b6000546001600160a01b0316331461080557604051639f216c1360e01b815260040160405180910390fd5b6000806108128686611dbc565b6001600160a01b038083166000908152600660209081526040808320848616845282528083208a84528252918290208251608081018452905461ffff8116825262010000810490941691810182905260ff600160b01b85048116151593820193909352600160b81b90930490911615156060830152929450909250906108ab57604051632573cfb960e21b815260040160405180910390fd5b8315158160600151151514156108d357604051626ee66560e11b815260040160405180910390fd5b6001600160a01b038084166000908152600660209081526040808320868516845282528083208984528252918290208054881515600160b81b027fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff90911617905583015190519116907f44cf35361c9ff3c8c1397ec6410d5495cc481feaef35c9af11da1a637107de4f9061096d90871515815260200190565b60405180910390a250505050505050565b6000546001600160a01b031633146109a957604051639f216c1360e01b815260040160405180910390fd5b60035460ff600160a01b909104161515811515146109da576040516302dbbca560e21b815260040160405180910390fd5b60038054600160a01b8315027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9091161790556040517fcdee7bf87b7a743b4cbe1d2d534c5248621b76f58460337e7fda92d5d23f412490610a4190831515815260200190565b60405180910390a150565b6000610a59600983611de5565b92915050565b6000546001600160a01b03163314610a8a57604051639f216c1360e01b815260040160405180910390fd5b806001600160a01b031663d3b9fbe46040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610ac557600080fd5b505af1158015610ad9573d6000803e3d6000fd5b5050505050565b6000546001600160a01b03163314610b0b57604051639f216c1360e01b815260040160405180910390fd5b610b16600982611e0a565b610b3e576040516303ce0ad960e01b81526001600160a01b038216600482015260240161058d565b6040516001600160a01b038216907f84cc2115995684dcb0cd3d3a9565e3d32f075de81db70c8dc3a719b2a47af67e90600090a250565b60075460609060f881901c8015610c23578067ffffffffffffffff811115610b9f57610b9f612940565b604051908082528060200260200182016040528015610bc8578160200160208202803683370190505b509250600060015b60648111610c205783811c60011660011415610c185780858381518110610bf957610bf9612956565b60200260200101818152505082826001019250821415610c1857610c20565b600101610bd0565b50505b505090565b600080610c3d6000546001600160a01b031690565b600354909150600160a01b900460ff16158015610c635750336001600160a01b03821614155b15610c8257604051627487d360e71b815233600482015260240161058d565b6002546001600160a01b031680610cac576040516328b4fcf960e21b815260040160405180910390fd5b610cb7600987611de5565b610cdf57604051638e888ef360e01b81526001600160a01b038716600482015260240161058d565b856001600160a01b0316876001600160a01b03161415610d1d57604051632f9b185360e01b81526001600160a01b038816600482015260240161058d565b610d308562ffffff168561ffff16611e1f565b50600080610d3e8989611dbc565b90925090506001600160a01b038216610d6a57604051632573cfb960e21b815260040160405180910390fd5b6001600160a01b0382811660009081526006602090815260408083208585168452825280832061ffff8b1684529091529020546201000090041615610ddf5760405163cb27a43560e01b81526001600160a01b03808b1660048301528916602482015261ffff8716604482015260640161058d565b61ffff861660009081526008602052604090205480610e1757604051637d9160bf60e11b815261ffff8816600482015260240161058d565b604080516001600160a01b038581166020808401919091529085168284015261ffff8a16606080840191909152835180840390910181526080909201909252805191012071ffffffffffffffffffffffffffffffffffff82169160f01c90610e7f8682611e5f565b60405163d32db43760e01b81526001600160a01b038e811660048301528d8116602483015262ffffff8d16604483015261ffff85166064830152608482018690529199509089169063d32db4379060a401600060405180830381600087803b158015610eea57600080fd5b505af1158015610efe573d6000803e3d6000fd5b5050505060405180608001604052808a61ffff168152602001896001600160a01b03168152602001886001600160a01b0316336001600160a01b031614151581526020016000151581525060066000876001600160a01b03166001600160a01b031681526020019081526020016000206000866001600160a01b03166001600160a01b0316815260200190815260200160002060008b61ffff16815260200190815260200160002060008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160000160166101000a81548160ff02191690831515021790555060608201518160000160176101000a81548160ff0219169083151502179055509050506005889080600181540180825580915050600190039060005260206000200160009091909190916101000a8154816001600160a01b0302191690836001600160a01b031602179055506000600b6000876001600160a01b03166001600160a01b031681526020019081526020016000206000866001600160a01b03166001600160a01b031681526020019081526020016000205490508961ffff166001901b8160001c1760001b90508060001c600160f81b6110f59190612928565b6001600160a01b038088166000908152600b602090815260408083208a8516845290915290209190915560055461ffff8c1692508d8216918f16907f2c8d104b27c6b7f4492017a6f5cf3803043688934ebcaa6a03540beeaf976aff908c906111609060019061296c565b604080516001600160a01b03909316835260208301919091520160405180910390a46040805161ffff808c168252601086901c811660208381019190915286901c811682840152603086901c8116606083015285831c8116608083015262ffffff605087901c811660a0840152606887901c90911660c0830152607886901c1660e082015290516001600160a01b038a169133917f63a7af39b7b68b9c3f2dfe93e5f32d9faecb4c6c98733bb608f757e62f816c0d918190036101000190a350505050505050949350505050565b606060008061123d8585611dbc565b6001600160a01b038281166000908152600b6020908152604080832093851683529290522054919350915060f881901c80156113f3578067ffffffffffffffff81111561128c5761128c612940565b6040519080825280602002602001820160405280156112de57816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816112aa5790505b509450600060015b606481116113f05783811c600116600114156113e8576001600160a01b03808716600090815260066020908152604080832089851684528252808320858452825291829020825160808082018552915461ffff811682526201000081049095169281019290925260ff600160b01b85048116151583850152600160b81b909404909316151560608201528151928301909152908061138384611f16565b61ffff16815260200182602001516001600160a01b03168152602001826040015115158152602001826060015115158152508884815181106113c7576113c7612956565b6020026020010181905250838360010193508314156113e657506113f0565b505b6001016112e6565b50505b5050505092915050565b6000546001600160a01b0316331461142857604051639f216c1360e01b815260040160405180910390fd5b6001546001600160a01b03166114515760405163ecfad6bf60e01b815260040160405180910390fd5b61145b6000611f43565b565b60408051608081018252600080825260208201819052918101829052606081019190915261148c848484611a9e565b949350505050565b6000546001600160a01b031633146114bf57604051639f216c1360e01b815260040160405180910390fd5b61145b6000611f8d565b600581815481106114d957600080fd5b6000918252602090912001546001600160a01b0316905081565b60006114ff6009611fe7565b905090565b61ffff811660009081526008602052604081205481908190819081908190819081908061154a57604051637d9160bf60e11b815261ffff8b16600482015260240161058d565b600061ffff82168b61ffff161461156057600080fd5b61157a61ffff611571601084612928565b925083831c1690565b995061158d61ffff611571601084612928565b98506115a061ffff611571601084612928565b97506115b361ffff611571601084612928565b96506115c762ffffff611571601084612928565b95506115da61ffff611571601884612928565b94506115ee62ffffff611571601084612928565b935060f082901c92505050919395975091939597565b6000546001600160a01b0316331461162f57604051639f216c1360e01b815260040160405180910390fd5b306001600160a01b0316816001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015611677573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169b9190612983565b6001600160a01b0316146116cd57604051630a3e70af60e11b81526001600160a01b038216600482015260240161058d565b6002546001600160a01b0390811690821681141561170957604051630ded3b9560e31b81526001600160a01b038316600482015260240161058d565b600280546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f900d0e3d359f50e4f923ecdc06b401e07dbb9f485e17b07bcfc91a13000b277e91015b60405180910390a15050565b6000546001600160a01b0316331461179457604051639f216c1360e01b815260040160405180910390fd5b6001600160a01b0381166117bb576040516391f3851560e01b815260040160405180910390fd5b6001546001600160a01b0316156117e55760405163716b1fbf60e01b815260040160405180910390fd5b6117ee81611f43565b50565b6000546001600160a01b0316331461181c57604051639f216c1360e01b815260040160405180910390fd5b611827600982611ff1565b61184f57604051638e888ef360e01b81526001600160a01b038216600482015260240161058d565b6040516001600160a01b038216907f0b767739217755d8af5a2ba75b181a19fa1750f8bb701f09311cb19a90140cb390600090a250565b6000546001600160a01b031633146118b157604051639f216c1360e01b815260040160405180910390fd5b61ffff81166000908152600860205260409020546118e857604051637d9160bf60e11b815261ffff8216600482015260240161058d565b6007546118fe600161ffff84161b60001961296c565b1661190d600160f81b8261296c565b600781905561ffff83166000818152600860205260408082208290555192935090917fdd86b848bb56ff540caa68683fa467d0e7eb5f8b2d44e4ee435742eeeae9be139190a25050565b6000546001600160a01b0316331461198257604051639f216c1360e01b815260040160405180910390fd5b6117ee81612006565b6000546001600160a01b031633146119b657604051639f216c1360e01b815260040160405180910390fd5b600454818114156119dd57604051631baa31e960e21b81526004810183905260240161058d565b67016345785d8a0000821115611a1757604051635e8988c160e01b81526004810183905267016345785d8a0000602482015260440161058d565b600482905560408051828152602081018490527f5c34e91c94c78b662a45d0bd4a25a4e32c584c54a45a76e4a4d43be27ba40e50910161175d565b6000610a596009836120c1565b6001546001600160a01b031633141580611a77575033155b15611a9557604051633982680960e11b815260040160405180910390fd5b61145b33611f8d565b604080516080810182526000808252602082018190529181018290526060810191909152611acc8484611dbc565b6001600160a01b03918216600090815260066020908152604080832093851683529281528282209582529485528190208151608081018352905461ffff811682526201000081049093169481019490945260ff600160b01b83048116151591850191909152600160b81b90910416151560608301525092915050565b600060018961ffff161080611b61575060648961ffff16115b15611b9357604051634f95635f60e11b81526001600482015261ffff8a1660248201526064604482018190520161058d565b8561ffff168761ffff1610611bc95760405163744d432160e11b815261ffff80891660048301528716602482015260440161058d565b6127108561ffff161115611bfe5760405163632afa6960e11b815261ffff86166004820152612710602482015260440161058d565b6109c48361ffff161115611c3357604051630d0ada2960e41b815261ffff841660048201526109c4602482015260440161058d565b6000611c4661ffff808c16908b166129a0565b611c55906402540be4006129a0565b90506000611c6c61ffff8c1662ffffff86166129a0565b90506000606462ffffff8816611c8284806129a0565b611c8c91906129a0565b611c9691906129bf565b905067016345785d8a0000611cab8285612928565b1115611ce657611cbb8184612928565b604051633fb210a760e21b8152600481019190915267016345785d8a0000602482015260440161058d565b50506040805171ffffff000000000000000000000000000000607886901b1660208201527fffff00000000000000000000000000000000000000000000000000000000000060f087811b821660318401527fffffff000000000000000000000000000000000000000000000000000000000060e88a901b16603384015289811b821660368401528a811b821660388401528b811b8216603a8401528c811b8216603c8401528d901b16603e820152019050604051602081830303815290604052611daf906129e1565b9998505050505050505050565b600080826001600160a01b0316846001600160a01b03161115611ddd579192915b509192909150565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b6000611e03836001600160a01b0384166120cd565b600062ffffff831115611e455760405163163d8bab60e21b815260040160405180910390fd5b627fffff19830161148c81611e598561211c565b90612162565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528360601b60148201527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006028820152826037826000f59150506001600160a01b038116610a595760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c6564000000000000000000604482015260640161058d565b8061ffff81168114611f3e5760405163506fbff560e01b81526004810183905260240161058d565b919050565b600180546001600160a01b0319166001600160a01b0383169081179091556040517f68f49b346b94582a8b5f9d10e3fe3365318fe8f191ff8dce7c59c6cad06b02f590600090a250565b600080546001600160a01b038381166001600160a01b031980841682178555600180549091169055604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610a59825490565b6000611e03836001600160a01b0384166123cd565b6001600160a01b03811661202d57604051632573cfb960e21b815260040160405180910390fd5b6003546001600160a01b0390811690821681141561206957604051634fcea97160e01b81526001600160a01b038316600482015260240161058d565b600380546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f15d80a013f22151bc7246e3bc132e12828cde19de98870475e3fa70840152721910161175d565b6000611e0383836124c0565b600081815260018301602052604081205461211457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610a59565b506000610a59565b600081158061212c575061271082115b1561214d576040516374da1e1160e11b81526004810183905260240161058d565b612710608083901b04600160801b0192915050565b600080808361217a5750600160801b9150610a599050565b5082600081121561218c579015906000035b6210000081101561238557600160801b9250846fffffffffffffffffffffffffffffffff8111156121bf57911591600019045b60018216156121d05792830260801c925b800260801c60028216156121e65792830260801c925b800260801c60048216156121fc5792830260801c925b800260801c60088216156122125792830260801c925b800260801c60108216156122285792830260801c925b800260801c602082161561223e5792830260801c925b800260801c60408216156122545792830260801c925b8002608090811c9082161561226b5792830260801c925b800260801c6101008216156122825792830260801c925b800260801c6102008216156122995792830260801c925b800260801c6104008216156122b05792830260801c925b800260801c6108008216156122c75792830260801c925b800260801c6110008216156122de5792830260801c925b800260801c6120008216156122f55792830260801c925b800260801c61400082161561230c5792830260801c925b800260801c6180008216156123235792830260801c925b800260801c6201000082161561233b5792830260801c925b800260801c620200008216156123535792830260801c925b800260801c6204000082161561236b5792830260801c925b800260801c620800008216156123835792830260801c925b505b826123ad57604051630e9c7d6160e31b8152600481018690526024810185905260440161058d565b816123b857826123c4565b6123c4836000196129bf565b95945050505050565b600081815260018301602052604081205480156124b65760006123f160018361296c565b85549091506000906124059060019061296c565b905081811461246a57600086600001828154811061242557612425612956565b906000526020600020015490508087600001848154811061244857612448612956565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061247b5761247b612a08565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610a59565b6000915050610a59565b60008260000182815481106124d7576124d7612956565b9060005260206000200154905092915050565b6001600160a01b03811681146117ee57600080fd5b803561ffff81168114611f3e57600080fd5b803562ffffff81168114611f3e57600080fd5b6000806000806000806000806000806101408b8d03121561254457600080fd5b8a3561254f816124ea565b995060208b013561255f816124ea565b985061256d60408c016124ff565b975061257b60608c016124ff565b965061258960808c016124ff565b955061259760a08c016124ff565b94506125a560c08c016124ff565b93506125b360e08c01612511565b92506125c26101008c016124ff565b91506125d16101208c01612511565b90509295989b9194979a5092959850565b60008060008060008060008060006101208a8c03121561260157600080fd5b61260a8a6124ff565b985061261860208b016124ff565b975061262660408b016124ff565b965061263460608b016124ff565b955061264260808b016124ff565b945061265060a08b01612511565b935061265e60c08b016124ff565b925061266c60e08b01612511565b915061267b6101008b016124ff565b90509295985092959850929598565b80358015158114611f3e57600080fd5b600080600080608085870312156126b057600080fd5b84356126bb816124ea565b935060208501356126cb816124ea565b9250604085013591506126e06060860161268a565b905092959194509250565b6000602082840312156126fd57600080fd5b611e038261268a565b60006020828403121561271857600080fd5b8135611e03816124ea565b6020808252825182820181905260009190848201906040850190845b8181101561275b5783518352928401929184019160010161273f565b50909695505050505050565b6000806000806080858703121561277d57600080fd5b8435612788816124ea565b93506020850135612798816124ea565b92506127a660408601612511565b91506126e0606086016124ff565b600080604083850312156127c757600080fd5b82356127d2816124ea565b915060208301356127e2816124ea565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561275b5761284e83855161ffff81511682526001600160a01b0360208201511660208301526040810151151560408301526060810151151560608301525050565b9284019260809290920191600101612809565b60008060006060848603121561287657600080fd5b8335612881816124ea565b92506020840135612891816124ea565b929592945050506040919091013590565b815161ffff1681526020808301516001600160a01b03169082015260408083015115159082015260608083015115159082015260808101610a59565b6000602082840312156128f057600080fd5b5035919050565b60006020828403121561290957600080fd5b611e03826124ff565b634e487b7160e01b600052601160045260246000fd5b6000821982111561293b5761293b612912565b500190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008282101561297e5761297e612912565b500390565b60006020828403121561299557600080fd5b8151611e03816124ea565b60008160001904831182151516156129ba576129ba612912565b500290565b6000826129dc57634e487b7160e01b600052601260045260246000fd5b500490565b80516020808301519190811015612a02576000198160200360031b1b821691505b50919050565b634e487b7160e01b600052603160045260246000fdfea26469706673582212203b9f852cba9b69a7ead4adbbe5d3e43b7890dce2e48797cee6fa9fbfe22e2e6f64736f6c634300080a0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000001119fbb02f38764cd90f2d9fb35fedcd8378ac2a0000000000000000000000000000000000000000000000000000048c27395000

-----Decoded View---------------
Arg [0] : _feeRecipient (address): 0x1119fbb02F38764CD90F2d9fB35FeDcd8378ac2A
Arg [1] : _flashLoanFee (uint256): 5000000000000

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000001119fbb02f38764cd90f2d9fb35fedcd8378ac2a
Arg [1] : 0000000000000000000000000000000000000000000000000000048c27395000


Block Transaction Gas Used Reward
view all blocks ##produced##

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

OVERVIEW

One-stop-shop decentralized trading on Avalanche.

Loading...
Loading

Validator Index Block Amount
View All Withdrawals

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

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