AVAX Price: $22.91 (+12.28%)
Gas: 1 nAVAX
 

Overview

AVAX Balance

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

AVAX Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Create LB Pair471711592024-06-25 15:51:11301 days ago1719330671IN
Trader Joe: LB Factory v2.1
0 AVAX0.0064773426.5
Create LB Pair471702702024-06-25 15:21:08301 days ago1719328868IN
Trader Joe: LB Factory v2.1
0 AVAX0.0069294326.5
Create LB Pair467406602024-06-15 7:44:51312 days ago1718437491IN
Trader Joe: LB Factory v2.1
0 AVAX0.006669725.5
Create LB Pair467206062024-06-14 19:57:44312 days ago1718395064IN
Trader Joe: LB Factory v2.1
0 AVAX0.0071727827.425
Create LB Pair467204902024-06-14 19:53:47312 days ago1718394827IN
Trader Joe: LB Factory v2.1
0 AVAX0.0065693426.8818
Create LB Pair467203822024-06-14 19:50:02312 days ago1718394602IN
Trader Joe: LB Factory v2.1
0 AVAX0.0069305426.5
Create LB Pair467130272024-06-14 15:39:27312 days ago1718379567IN
Trader Joe: LB Factory v2.1
0 AVAX0.0067038227.425
Create LB Pair467129332024-06-14 15:36:13312 days ago1718379373IN
Trader Joe: LB Factory v2.1
0 AVAX0.0069303326.5
Create LB Pair467066502024-06-14 12:01:45312 days ago1718366505IN
Trader Joe: LB Factory v2.1
0 AVAX0.0069305426.5
Create LB Pair466277762024-06-12 14:19:25314 days ago1718201965IN
Trader Joe: LB Factory v2.1
0 AVAX0.0071907527.5
Create LB Pair465956282024-06-11 19:43:24315 days ago1718135004IN
Trader Joe: LB Factory v2.1
0 AVAX0.0061117725.0000001
Create LB Pair465932162024-06-11 18:21:20315 days ago1718130080IN
Trader Joe: LB Factory v2.1
0 AVAX0.0065993927
Create LB Pair465931482024-06-11 18:19:00315 days ago1718129940IN
Trader Joe: LB Factory v2.1
0 AVAX0.0099072340.53
Create LB Pair465546822024-06-10 20:07:08316 days ago1718050028IN
Trader Joe: LB Factory v2.1
0 AVAX0.0070621727
Create LB Pair465248882024-06-10 3:03:16317 days ago1717988596IN
Trader Joe: LB Factory v2.1
0 AVAX0.0069305726.5
Create LB Pair464624772024-06-08 14:25:59318 days ago1717856759IN
Trader Joe: LB Factory v2.1
0 AVAX0.00657126.88
Create LB Pair464271392024-06-07 17:58:14319 days ago1717783094IN
Trader Joe: LB Factory v2.1
0 AVAX0.0070980227.14683506
Create LB Pair463039022024-06-04 18:59:20322 days ago1717527560IN
Trader Joe: LB Factory v2.1
0 AVAX0.0069307326.5
Create LB Pair462945082024-06-04 13:38:53322 days ago1717508333IN
Trader Joe: LB Factory v2.1
0 AVAX0.006930726.5
Create LB Pair462334912024-06-03 1:59:45324 days ago1717379985IN
Trader Joe: LB Factory v2.1
0 AVAX0.0065390525
Create LB Pair461573352024-06-01 5:11:37326 days ago1717218697IN
Trader Joe: LB Factory v2.1
0 AVAX0.0066689625.5
Create LB Pair460965812024-05-30 17:46:45327 days ago1717091205IN
Trader Joe: LB Factory v2.1
0 AVAX0.0065999327
Create LB Pair459815762024-05-27 23:03:12330 days ago1716850992IN
Trader Joe: LB Factory v2.1
0 AVAX0.0065382725.0000001
Create LB Pair459751092024-05-27 19:17:43330 days ago1716837463IN
Trader Joe: LB Factory v2.1
0 AVAX0.0070612527
Create LB Pair459186882024-05-26 10:31:00332 days ago1716719460IN
Trader Joe: LB Factory v2.1
0 AVAX0.0074529728.5
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
471711592024-06-25 15:51:11301 days ago1719330671
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
471702702024-06-25 15:21:08301 days ago1719328868
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
467406602024-06-15 7:44:51312 days ago1718437491
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
467206062024-06-14 19:57:44312 days ago1718395064
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
467204902024-06-14 19:53:47312 days ago1718394827
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
467203822024-06-14 19:50:02312 days ago1718394602
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
467130272024-06-14 15:39:27312 days ago1718379567
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
467129332024-06-14 15:36:13312 days ago1718379373
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
467066502024-06-14 12:01:45312 days ago1718366505
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
466277762024-06-12 14:19:25314 days ago1718201965
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
465956282024-06-11 19:43:24315 days ago1718135004
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
465932162024-06-11 18:21:20315 days ago1718130080
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
465931482024-06-11 18:19:00315 days ago1718129940
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
465546822024-06-10 20:07:08316 days ago1718050028
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
465248882024-06-10 3:03:16317 days ago1717988596
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
464624772024-06-08 14:25:59318 days ago1717856759
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
464271392024-06-07 17:58:14319 days ago1717783094
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
463039022024-06-04 18:59:20322 days ago1717527560
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
462945082024-06-04 13:38:53322 days ago1717508333
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
462334912024-06-03 1:59:45324 days ago1717379985
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
461573352024-06-01 5:11:37326 days ago1717218697
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
460965812024-05-30 17:46:45327 days ago1717091205
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
459815762024-05-27 23:03:12330 days ago1716850992
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
459751092024-05-27 19:17:43330 days ago1716837463
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
459186882024-05-26 10:31:00332 days ago1716719460
Trader Joe: LB Factory v2.1
 Contract Creation0 AVAX
View All Internal 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
File 1 of 19 : LBFactory.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import {EnumerableSet} from "openzeppelin/utils/structs/EnumerableSet.sol";
import {EnumerableMap} from "openzeppelin/utils/structs/EnumerableMap.sol";
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";

import {PairParameterHelper} from "./libraries/PairParameterHelper.sol";
import {Encoded} from "./libraries/math/Encoded.sol";
import {ImmutableClone} from "./libraries/ImmutableClone.sol";
import {PendingOwnable} from "./libraries/PendingOwnable.sol";
import {PriceHelper} from "./libraries/PriceHelper.sol";
import {SafeCast} from "./libraries/math/SafeCast.sol";

import {ILBFactory} from "./interfaces/ILBFactory.sol";
import {ILBPair} from "./interfaces/ILBPair.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 `isOpen` is `true`, only the owner of the factory can create pairs.
 */
contract LBFactory is PendingOwnable, ILBFactory {
    using SafeCast for uint256;
    using Encoded for bytes32;
    using PairParameterHelper for bytes32;
    using EnumerableSet for EnumerableSet.AddressSet;
    using EnumerableSet for EnumerableSet.UintSet;
    using EnumerableMap for EnumerableMap.UintToUintMap;

    uint256 private constant _OFFSET_IS_PRESET_OPEN = 255;

    uint256 private constant _MIN_BIN_STEP = 1; // 0.001%

    uint256 private constant _MAX_FLASHLOAN_FEE = 0.1e18; // 10%

    address private _feeRecipient;
    uint256 private _flashLoanFee;

    address private _lbPairImplementation;

    ILBPair[] private _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;

    EnumerableMap.UintToUintMap private _presets;
    EnumerableSet.AddressSet private _quoteAssetWhitelist;

    /**
     * @dev Mapping from a (tokenA, tokenB) to a set of available bin steps, this is used to keep track of the
     * bin steps that are already used for a pair.
     * 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 => EnumerableSet.UintSet)) 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_FLASHLOAN_FEE) revert LBFactory__FlashLoanFeeAboveMax(flashLoanFee, _MAX_FLASHLOAN_FEE);

        _setFeeRecipient(feeRecipient);

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

    /**
     * @notice Get the minimum bin step a pair can have
     * @return minBinStep
     */
    function getMinBinStep() external pure override returns (uint256 minBinStep) {
        return _MIN_BIN_STEP;
    }

    /**
     * @notice Get the protocol fee recipient
     * @return feeRecipient
     */
    function getFeeRecipient() external view override returns (address feeRecipient) {
        return _feeRecipient;
    }

    /**
     * @notice Get the maximum fee percentage for flashLoans
     * @return maxFee
     */
    function getMaxFlashLoanFee() external pure override returns (uint256 maxFee) {
        return _MAX_FLASHLOAN_FEE;
    }

    /**
     * @notice Get the fee for flash loans, in 1e18
     * @return flashLoanFee The fee for flash loans, in 1e18
     */
    function getFlashLoanFee() external view override returns (uint256 flashLoanFee) {
        return _flashLoanFee;
    }

    /**
     * @notice Get the address of the LBPair implementation
     * @return lbPairImplementation
     */
    function getLBPairImplementation() external view override returns (address lbPairImplementation) {
        return _lbPairImplementation;
    }

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

    /**
     * @notice View function to return the LBPair created at index `index`
     * @param index The index
     * @return lbPair The address of the LBPair at index `index`
     */
    function getLBPairAtIndex(uint256 index) external view override returns (ILBPair lbPair) {
        return _allLBPairs[index];
    }

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

    /**
     * @notice View function to return the quote asset whitelisted at index `index`
     * @param index The index
     * @return asset The address of the quoteAsset at index `index`
     */
    function getQuoteAssetAtIndex(uint256 index) external view override returns (IERC20 asset) {
        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 isQuote Whether the token is a quote asset or not
     */
    function isQuoteAsset(IERC20 token) external view override returns (bool isQuote) {
        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 lbPairInformation The LBPairInformation
     */
    function getLBPairInformation(IERC20 tokenA, IERC20 tokenB, uint256 binStep)
        external
        view
        override
        returns (LBPairInformation memory lbPairInformation)
    {
        return _getLBPairInformation(tokenA, tokenB, binStep);
    }

    /**
     * @notice View function to return the different parameters of the preset
     * Will revert if the preset doesn't exist
     * @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 maxVolatilityAccumulator The max volatility accumulator of the preset
     * @return isOpen Whether the preset is open or not
     */
    function getPreset(uint256 binStep)
        external
        view
        override
        returns (
            uint256 baseFactor,
            uint256 filterPeriod,
            uint256 decayPeriod,
            uint256 reductionFactor,
            uint256 variableFeeControl,
            uint256 protocolShare,
            uint256 maxVolatilityAccumulator,
            bool isOpen
        )
    {
        if (!_presets.contains(binStep)) revert LBFactory__BinStepHasNoPreset(binStep);

        bytes32 preset = bytes32(_presets.get(binStep));

        baseFactor = preset.getBaseFactor();
        filterPeriod = preset.getFilterPeriod();
        decayPeriod = preset.getDecayPeriod();
        reductionFactor = preset.getReductionFactor();
        variableFeeControl = preset.getVariableFeeControl();
        protocolShare = preset.getProtocolShare();
        maxVolatilityAccumulator = preset.getMaxVolatilityAccumulator();

        isOpen = preset.decodeBool(_OFFSET_IS_PRESET_OPEN);
    }

    /**
     * @notice View function to return the list of available binStep with a preset
     * @return binStepWithPreset The list of binStep
     */
    function getAllBinSteps() external view override returns (uint256[] memory binStepWithPreset) {
        return _presets.keys();
    }

    /**
     * @notice View function to return the list of open binSteps
     * @return openBinStep The list of open binSteps
     */
    function getOpenBinSteps() external view override returns (uint256[] memory openBinStep) {
        uint256 length = _presets.length();

        if (length > 0) {
            openBinStep = new uint256[](length);

            uint256 index;

            for (uint256 i; i < length; ++i) {
                (uint256 binStep, uint256 preset) = _presets.at(i);

                if (_isPresetOpen(bytes32(preset))) {
                    openBinStep[index] = binStep;
                    index++;
                }
            }

            if (index < length) {
                assembly {
                    mstore(openBinStep, index)
                }
            }
        }
    }

    /**
     * @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);

            EnumerableSet.UintSet storage addressSet = _availableLBPairBinSteps[tokenA][tokenB];

            uint256 length = addressSet.length();

            if (length > 0) {
                lbPairsAvailable = new LBPairInformation[](length);

                mapping(uint256 => LBPairInformation) storage lbPairsInfo = _lbPairsInfo[tokenA][tokenB];

                for (uint256 i = 0; i < length; ++i) {
                    uint16 binStep = addressSet.at(i).safe16();

                    lbPairsAvailable[i] = LBPairInformation({
                        binStep: binStep,
                        LBPair: lbPairsInfo[binStep].LBPair,
                        createdByOwner: lbPairsInfo[binStep].createdByOwner,
                        ignoredForRouting: lbPairsInfo[binStep].ignoredForRouting
                    });
                }
            }
        }
    }

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

        address oldLBPairImplementation = _lbPairImplementation;
        if (oldLBPairImplementation == newLBPairImplementation) {
            revert LBFactory__SameImplementation(newLBPairImplementation);
        }

        _lbPairImplementation = newLBPairImplementation;

        emit LBPairImplementationSet(oldLBPairImplementation, newLBPairImplementation);
    }

    /**
     * @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 / 10_000)
     * @return pair The address of the newly created LBPair
     */
    function createLBPair(IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep)
        external
        override
        returns (ILBPair pair)
    {
        if (!_presets.contains(binStep)) revert LBFactory__BinStepHasNoPreset(binStep);

        bytes32 preset = bytes32(_presets.get(binStep));
        bool isOwner = msg.sender == owner();

        if (!_isPresetOpen(preset) && !isOwner) {
            revert LBFactory__PresetIsLockedForUsers(msg.sender, binStep);
        }

        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
        PriceHelper.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);
        }

        {
            address implementation = _lbPairImplementation;

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

            pair = ILBPair(
                ImmutableClone.cloneDeterministic(
                    implementation,
                    abi.encodePacked(tokenX, tokenY, binStep),
                    keccak256(abi.encode(tokenA, tokenB, binStep))
                )
            );
        }

        pair.initialize(
            preset.getBaseFactor(),
            preset.getFilterPeriod(),
            preset.getDecayPeriod(),
            preset.getReductionFactor(),
            preset.getVariableFeeControl(),
            preset.getProtocolShare(),
            preset.getMaxVolatilityAccumulator(),
            activeId
        );

        _lbPairsInfo[tokenA][tokenB][binStep] =
            LBPairInformation({binStep: binStep, LBPair: pair, createdByOwner: isOwner, ignoredForRouting: false});

        _allLBPairs.push(pair);
        _availableLBPairBinSteps[tokenA][tokenB].add(binStep);

        emit LBPairCreated(tokenX, tokenY, binStep, pair, _allLBPairs.length - 1);
    }

    /**
     * @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, uint16 binStep, bool ignored) external override onlyOwner {
        (IERC20 tokenA, IERC20 tokenB) = _sortTokens(tokenX, tokenY);

        LBPairInformation memory pairInformation = _lbPairsInfo[tokenA][tokenB][binStep];
        if (address(pairInformation.LBPair) == address(0)) {
            revert LBFactory__LBPairDoesNotExist(tokenX, tokenY, binStep);
        }

        if (pairInformation.ignoredForRouting == ignored) revert LBFactory__LBPairIgnoredIsAlreadyInTheSameState();

        _lbPairsInfo[tokenA][tokenB][binStep].ignoredForRouting = ignored;

        emit LBPairIgnoredStateChanged(pairInformation.LBPair, ignored);
    }

    /**
     * @notice Sets the preset parameters of a bin step
     * @param binStep The bin step in basis point, used to calculate the price
     * @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 decayed, by the reduction factor
     * @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 maxVolatilityAccumulator The max value of the volatility accumulator
     */
    function setPreset(
        uint16 binStep,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator,
        bool isOpen
    ) external override onlyOwner {
        if (binStep < _MIN_BIN_STEP) revert LBFactory__BinStepTooLow(binStep);

        bytes32 preset = bytes32(0).setStaticFeeParameters(
            baseFactor,
            filterPeriod,
            decayPeriod,
            reductionFactor,
            variableFeeControl,
            protocolShare,
            maxVolatilityAccumulator
        );

        if (isOpen) {
            preset = preset.setBool(true, _OFFSET_IS_PRESET_OPEN);
        }

        _presets.set(binStep, uint256(preset));

        emit PresetSet(
            binStep,
            baseFactor,
            filterPeriod,
            decayPeriod,
            reductionFactor,
            variableFeeControl,
            protocolShare,
            maxVolatilityAccumulator
            );

        emit PresetOpenStateChanged(binStep, isOpen);
    }

    /**
     * @notice Sets if the preset is open or not to be used by users
     * @param binStep The bin step in basis point, used to calculate the price
     * @param isOpen Whether the preset is open or not
     */
    function setPresetOpenState(uint16 binStep, bool isOpen) external override onlyOwner {
        if (!_presets.contains(binStep)) revert LBFactory__BinStepHasNoPreset(binStep);

        bytes32 preset = bytes32(_presets.get(binStep));

        if (preset.decodeBool(_OFFSET_IS_PRESET_OPEN) == isOpen) {
            revert LBFactory__PresetOpenStateIsAlreadyInTheSameState();
        }

        _presets.set(binStep, uint256(preset.setBool(isOpen, _OFFSET_IS_PRESET_OPEN)));

        emit PresetOpenStateChanged(binStep, isOpen);
    }

    /**
     * @notice Remove the preset linked to a binStep
     * @param binStep The bin step to remove
     */
    function removePreset(uint16 binStep) external override onlyOwner {
        if (!_presets.remove(binStep)) revert LBFactory__BinStepHasNoPreset(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 the price
     * @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 decayed, by the reduction factor
     * @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 maxVolatilityAccumulator The max value of volatility accumulator
     */
    function setFeesParametersOnPair(
        IERC20 tokenX,
        IERC20 tokenY,
        uint16 binStep,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator
    ) external override onlyOwner {
        ILBPair lbPair = _getLBPairInformation(tokenX, tokenY, binStep).LBPair;

        if (address(lbPair) == address(0)) revert LBFactory__LBPairNotCreated(tokenX, tokenY, binStep);

        lbPair.setStaticFeeParameters(
            baseFactor,
            filterPeriod,
            decayPeriod,
            reductionFactor,
            variableFeeControl,
            protocolShare,
            maxVolatilityAccumulator
        );
    }

    /**
     * @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_FLASHLOAN_FEE) revert LBFactory__FlashLoanFeeAboveMax(flashLoanFee, _MAX_FLASHLOAN_FEE);

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

    /**
     * @notice Function to add an asset to the whitelist of quote assets
     * @param quoteAsset The quote asset (e.g: NATIVE, 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: NATIVE, USDC...)
     */
    function removeQuoteAsset(IERC20 quoteAsset) external override onlyOwner {
        if (!_quoteAssetWhitelist.remove(address(quoteAsset))) revert LBFactory__QuoteAssetNotWhitelisted(quoteAsset);

        emit QuoteAssetRemoved(quoteAsset);
    }

    function _isPresetOpen(bytes32 preset) internal pure returns (bool) {
        return preset.decodeBool(_OFFSET_IS_PRESET_OPEN);
    }

    /**
     * @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 pair) external override onlyOwner {
        pair.forceDecay();
    }

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

File 2 of 19 : IERC20.sol
// 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);
}

File 3 of 19 : EnumerableMap.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.

pragma solidity ^0.8.0;

import "./EnumerableSet.sol";

/**
 * @dev Library for managing an enumerable variant of Solidity's
 * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
 * type.
 *
 * Maps have the following properties:
 *
 * - Entries are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Entries are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableMap for EnumerableMap.UintToAddressMap;
 *
 *     // Declare a set state variable
 *     EnumerableMap.UintToAddressMap private myMap;
 * }
 * ```
 *
 * The following map types are supported:
 *
 * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
 * - `address -> uint256` (`AddressToUintMap`) since v4.6.0
 * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
 * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
 * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
 *
 * [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 EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableMap.
 * ====
 */
library EnumerableMap {
    using EnumerableSet for EnumerableSet.Bytes32Set;

    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Map type with
    // bytes32 keys and values.
    // The Map implementation uses private functions, and user-facing
    // implementations (such as Uint256ToAddressMap) are just wrappers around
    // the underlying Map.
    // This means that we can only create new EnumerableMaps for types that fit
    // in bytes32.

    struct Bytes32ToBytes32Map {
        // Storage of keys
        EnumerableSet.Bytes32Set _keys;
        mapping(bytes32 => bytes32) _values;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
        map._values[key] = value;
        return map._keys.add(key);
    }

    /**
     * @dev Removes a key-value pair from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
        delete map._values[key];
        return map._keys.remove(key);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
        return map._keys.contains(key);
    }

    /**
     * @dev Returns the number of key-value pairs in the map. O(1).
     */
    function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
        return map._keys.length();
    }

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

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
        bytes32 value = map._values[key];
        if (value == bytes32(0)) {
            return (contains(map, key), bytes32(0));
        } else {
            return (true, value);
        }
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
        bytes32 value = map._values[key];
        require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key");
        return value;
    }

    /**
     * @dev Same as {get}, with a custom error message when `key` is not in the map.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryGet}.
     */
    function get(
        Bytes32ToBytes32Map storage map,
        bytes32 key,
        string memory errorMessage
    ) internal view returns (bytes32) {
        bytes32 value = map._values[key];
        require(value != 0 || contains(map, key), errorMessage);
        return value;
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
        return map._keys.values();
    }

    // UintToUintMap

    struct UintToUintMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
        return set(map._inner, bytes32(key), bytes32(value));
    }

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

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

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(UintToUintMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
        (bytes32 key, bytes32 value) = at(map._inner, index);
        return (uint256(key), uint256(value));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
        (bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
        return (success, uint256(value));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
        return uint256(get(map._inner, bytes32(key)));
    }

    /**
     * @dev Same as {get}, with a custom error message when `key` is not in the map.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryGet}.
     */
    function get(UintToUintMap storage map, uint256 key, string memory errorMessage) internal view returns (uint256) {
        return uint256(get(map._inner, bytes32(key), errorMessage));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
        bytes32[] memory store = keys(map._inner);
        uint256[] memory result;

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

        return result;
    }

    // UintToAddressMap

    struct UintToAddressMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
        return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
    }

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

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

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(UintToAddressMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
        (bytes32 key, bytes32 value) = at(map._inner, index);
        return (uint256(key), address(uint160(uint256(value))));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
        (bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
        return (success, address(uint160(uint256(value))));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
        return address(uint160(uint256(get(map._inner, bytes32(key)))));
    }

    /**
     * @dev Same as {get}, with a custom error message when `key` is not in the map.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryGet}.
     */
    function get(
        UintToAddressMap storage map,
        uint256 key,
        string memory errorMessage
    ) internal view returns (address) {
        return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage))));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
        bytes32[] memory store = keys(map._inner);
        uint256[] memory result;

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

        return result;
    }

    // AddressToUintMap

    struct AddressToUintMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
        return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
    }

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

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

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(AddressToUintMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
        (bytes32 key, bytes32 value) = at(map._inner, index);
        return (address(uint160(uint256(key))), uint256(value));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
        (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
        return (success, uint256(value));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
        return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
    }

    /**
     * @dev Same as {get}, with a custom error message when `key` is not in the map.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryGet}.
     */
    function get(
        AddressToUintMap storage map,
        address key,
        string memory errorMessage
    ) internal view returns (uint256) {
        return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
        bytes32[] memory store = keys(map._inner);
        address[] memory result;

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

        return result;
    }

    // Bytes32ToUintMap

    struct Bytes32ToUintMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
        return set(map._inner, key, bytes32(value));
    }

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

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

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
        (bytes32 key, bytes32 value) = at(map._inner, index);
        return (key, uint256(value));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
        (bool success, bytes32 value) = tryGet(map._inner, key);
        return (success, uint256(value));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
        return uint256(get(map._inner, key));
    }

    /**
     * @dev Same as {get}, with a custom error message when `key` is not in the map.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryGet}.
     */
    function get(
        Bytes32ToUintMap storage map,
        bytes32 key,
        string memory errorMessage
    ) internal view returns (uint256) {
        return uint256(get(map._inner, key, errorMessage));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
        bytes32[] memory store = keys(map._inner);
        bytes32[] memory result;

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

        return result;
    }
}

File 4 of 19 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

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) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

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

        return result;
    }

    // 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 in 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 : ILBFactory.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";

import {ILBPair} from "./ILBPair.sol";
import {IPendingOwnable} from "./IPendingOwnable.sol";

/**
 * @title Liquidity Book Factory Interface
 * @author Trader Joe
 * @notice Required interface of LBFactory contract
 */
interface ILBFactory is IPendingOwnable {
    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__LBPairDoesNotExist(IERC20 tokenX, IERC20 tokenY, uint256 binStep);
    error LBFactory__LBPairNotCreated(IERC20 tokenX, IERC20 tokenY, uint256 binStep);
    error LBFactory__FlashLoanFeeAboveMax(uint256 fees, uint256 maxFees);
    error LBFactory__BinStepTooLow(uint256 binStep);
    error LBFactory__PresetIsLockedForUsers(address user, uint256 binStep);
    error LBFactory__LBPairIgnoredIsAlreadyInTheSameState();
    error LBFactory__BinStepHasNoPreset(uint256 binStep);
    error LBFactory__PresetOpenStateIsAlreadyInTheSameState();
    error LBFactory__SameFeeRecipient(address feeRecipient);
    error LBFactory__SameFlashLoanFee(uint256 flashLoanFee);
    error LBFactory__LBPairSafetyCheckFailed(address LBPairImplementation);
    error LBFactory__SameImplementation(address LBPairImplementation);
    error LBFactory__ImplementationNotSet();

    /**
     * @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 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 maxVolatilityAccumulator
    );

    event PresetOpenStateChanged(uint256 indexed binStep, bool indexed isOpen);

    event PresetRemoved(uint256 indexed binStep);

    event QuoteAssetAdded(IERC20 indexed quoteAsset);

    event QuoteAssetRemoved(IERC20 indexed quoteAsset);

    function getMinBinStep() external pure returns (uint256);

    function getFeeRecipient() external view returns (address);

    function getMaxFlashLoanFee() external pure returns (uint256);

    function getFlashLoanFee() external view returns (uint256);

    function getLBPairImplementation() external view returns (address);

    function getNumberOfLBPairs() external view returns (uint256);

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

    function getNumberOfQuoteAssets() external view returns (uint256);

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

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

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

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

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

    function getOpenBinSteps() external view returns (uint256[] memory openBinStep);

    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, uint16 binStep, bool ignored) external;

    function setPreset(
        uint16 binStep,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator,
        bool isOpen
    ) external;

    function setPresetOpenState(uint16 binStep, bool isOpen) 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 maxVolatilityAccumulator
    ) external;

    function setFeeRecipient(address feeRecipient) external;

    function setFlashLoanFee(uint256 flashLoanFee) external;

    function addQuoteAsset(IERC20 quoteAsset) external;

    function removeQuoteAsset(IERC20 quoteAsset) external;

    function forceDecay(ILBPair lbPair) external;
}

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

pragma solidity 0.8.10;

import {IERC20} from "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 tokenX,
        IERC20 tokenY,
        bytes32 amounts,
        bytes32 totalFees,
        bytes calldata data
    ) external returns (bytes32);
}

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

pragma solidity 0.8.10;

import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";

import {ILBFactory} from "./ILBFactory.sol";
import {ILBFlashLoanCallback} from "./ILBFlashLoanCallback.sol";
import {ILBToken} from "./ILBToken.sol";

interface ILBPair is ILBToken {
    error LBPair__ZeroBorrowAmount();
    error LBPair__AddressZero();
    error LBPair__AlreadyInitialized();
    error LBPair__EmptyMarketConfigs();
    error LBPair__FlashLoanCallbackFailed();
    error LBPair__FlashLoanInsufficientAmount();
    error LBPair__InsufficientAmountIn();
    error LBPair__InsufficientAmountOut();
    error LBPair__InvalidInput();
    error LBPair__InvalidStaticFeeParameters();
    error LBPair__OnlyFactory();
    error LBPair__OnlyProtocolFeeRecipient();
    error LBPair__OutOfLiquidity();
    error LBPair__TokenNotSupported();
    error LBPair__ZeroAmount(uint24 id);
    error LBPair__ZeroAmountsOut(uint24 id);
    error LBPair__ZeroShares(uint24 id);
    error LBPair__MaxTotalFeeExceeded();

    struct MintArrays {
        uint256[] ids;
        bytes32[] amounts;
        uint256[] liquidityMinted;
    }

    event DepositedToBins(address indexed sender, address indexed to, uint256[] ids, bytes32[] amounts);

    event WithdrawnFromBins(address indexed sender, address indexed to, uint256[] ids, bytes32[] amounts);

    event CompositionFees(address indexed sender, uint24 id, bytes32 totalFees, bytes32 protocolFees);

    event CollectedProtocolFees(address indexed feeRecipient, bytes32 protocolFees);

    event Swap(
        address indexed sender,
        address indexed to,
        uint24 id,
        bytes32 amountsIn,
        bytes32 amountsOut,
        uint24 volatilityAccumulator,
        bytes32 totalFees,
        bytes32 protocolFees
    );

    event StaticFeeParametersSet(
        address indexed sender,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator
    );

    event FlashLoan(
        address indexed sender,
        ILBFlashLoanCallback indexed receiver,
        uint24 activeId,
        bytes32 amounts,
        bytes32 totalFees,
        bytes32 protocolFees
    );

    event OracleLengthIncreased(address indexed sender, uint16 oracleLength);

    event ForcedDecay(address indexed sender, uint24 idReference, uint24 volatilityReference);

    function initialize(
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator,
        uint24 activeId
    ) external;

    function getFactory() external view returns (ILBFactory factory);

    function getTokenX() external view returns (IERC20 tokenX);

    function getTokenY() external view returns (IERC20 tokenY);

    function getBinStep() external view returns (uint16 binStep);

    function getReserves() external view returns (uint128 reserveX, uint128 reserveY);

    function getActiveId() external view returns (uint24 activeId);

    function getBin(uint24 id) external view returns (uint128 binReserveX, uint128 binReserveY);

    function getNextNonEmptyBin(bool swapForY, uint24 id) external view returns (uint24 nextId);

    function getProtocolFees() external view returns (uint128 protocolFeeX, uint128 protocolFeeY);

    function getStaticFeeParameters()
        external
        view
        returns (
            uint16 baseFactor,
            uint16 filterPeriod,
            uint16 decayPeriod,
            uint16 reductionFactor,
            uint24 variableFeeControl,
            uint16 protocolShare,
            uint24 maxVolatilityAccumulator
        );

    function getVariableFeeParameters()
        external
        view
        returns (uint24 volatilityAccumulator, uint24 volatilityReference, uint24 idReference, uint40 timeOfLastUpdate);

    function getOracleParameters()
        external
        view
        returns (uint8 sampleLifetime, uint16 size, uint16 activeSize, uint40 lastUpdated, uint40 firstTimestamp);

    function getOracleSampleAt(uint40 lookupTimestamp)
        external
        view
        returns (uint64 cumulativeId, uint64 cumulativeVolatility, uint64 cumulativeBinCrossed);

    function getPriceFromId(uint24 id) external view returns (uint256 price);

    function getIdFromPrice(uint256 price) external view returns (uint24 id);

    function getSwapIn(uint128 amountOut, bool swapForY)
        external
        view
        returns (uint128 amountIn, uint128 amountOutLeft, uint128 fee);

    function getSwapOut(uint128 amountIn, bool swapForY)
        external
        view
        returns (uint128 amountInLeft, uint128 amountOut, uint128 fee);

    function swap(bool swapForY, address to) external returns (bytes32 amountsOut);

    function flashLoan(ILBFlashLoanCallback receiver, bytes32 amounts, bytes calldata data) external;

    function mint(address to, bytes32[] calldata liquidityConfigs, address refundTo)
        external
        returns (bytes32 amountsReceived, bytes32 amountsLeft, uint256[] memory liquidityMinted);

    function burn(address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn)
        external
        returns (bytes32[] memory amounts);

    function collectProtocolFees() external returns (bytes32 collectedProtocolFees);

    function increaseOracleLength(uint16 newLength) external;

    function setStaticFeeParameters(
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator
    ) external;

    function forceDecay() external;
}

File 8 of 19 : ILBToken.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/**
 * @title Liquidity Book Token Interface
 * @author Trader Joe
 * @notice Interface to interact with the LBToken.
 */
interface ILBToken {
    error LBToken__AddressThisOrZero();
    error LBToken__InvalidLength();
    error LBToken__SelfApproval(address owner);
    error LBToken__SpenderNotApproved(address from, address spender);
    error LBToken__TransferExceedsBalance(address from, uint256 id, uint256 amount);
    error LBToken__BurnExceedsBalance(address from, uint256 id, uint256 amount);

    event TransferBatch(
        address indexed sender, address indexed from, address indexed to, uint256[] ids, uint256[] amounts
    );

    event ApprovalForAll(address indexed account, address indexed sender, bool approved);

    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function totalSupply(uint256 id) external view returns (uint256);

    function balanceOf(address account, uint256 id) external view returns (uint256);

    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    function isApprovedForAll(address owner, address spender) external view returns (bool);

    function approveForAll(address spender, bool approved) external;

    function batchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts) external;
}

File 9 of 19 : IPendingOwnable.sol
// 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 {
    error PendingOwnable__AddressZero();
    error PendingOwnable__NoPendingOwner();
    error PendingOwnable__NotOwner();
    error PendingOwnable__NotPendingOwner();
    error PendingOwnable__PendingOwnerAlreadySet();

    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;
}

File 10 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 {
    uint8 internal constant SCALE_OFFSET = 128;
    uint256 internal constant SCALE = 1 << SCALE_OFFSET;

    uint256 internal constant PRECISION = 1e18;
    uint256 internal constant SQUARED_PRECISION = PRECISION * PRECISION;

    uint256 internal constant MAX_FEE = 0.1e18; // 10%
    uint256 internal constant MAX_PROTOCOL_SHARE = 2_500; // 25% of the fee

    uint256 internal constant BASIS_POINT_MAX = 10_000;

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

File 11 of 19 : ImmutableClone.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/**
 * @title Liquidity Book Immutable Clone Library
 * @notice Minimal immutable proxy library.
 * @author Trader Joe
 * @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol)
 * @author Minimal proxy by 0age (https://github.com/0age)
 * @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie
 * (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args)
 * @dev Minimal proxy:
 * Although the sw0nt pattern saves 5 gas over the erc-1167 pattern during runtime,
 * it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern,
 * which saves 4 gas over the erc-1167 pattern during runtime, and has the smallest bytecode.
 * @dev Clones with immutable args (CWIA):
 * The implementation of CWIA here doesn't implements a `receive()` as it is not needed for LB.
 */
library ImmutableClone {
    error DeploymentFailed();
    error PackedDataTooBig();

    /**
     * @dev Deploys a deterministic clone of `implementation` using immutable arguments encoded in `data`, with `salt`
     * @param implementation The address of the implementation
     * @param data The encoded immutable arguments
     * @param salt The salt
     */
    function cloneDeterministic(address implementation, bytes memory data, bytes32 salt)
        internal
        returns (address instance)
    {
        assembly {
            // Compute the boundaries of the data and cache the memory slots around it.
            let mBefore2 := mload(sub(data, 0x40))
            let mBefore1 := mload(sub(data, 0x20))
            let dataLength := mload(data)
            let dataEnd := add(add(data, 0x20), dataLength)
            let mAfter1 := mload(dataEnd)

            // +2 bytes for telling how much data there is appended to the call.
            let extraLength := add(dataLength, 2)
            // The `creationSize` is `extraLength + 63`
            // The `runSize` is `creationSize - 10`.

            // if `extraLength` is greater than `0xffca` revert as the `creationSize` would be greater than `0xffff`.
            if gt(extraLength, 0xffca) {
                // Store the function selector of `PackedDataTooBig()`.
                mstore(0x00, 0xc8c78139)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            /**
             * ---------------------------------------------------------------------------------------------------+
             * CREATION (10 bytes)                                                                                |
             * ---------------------------------------------------------------------------------------------------|
             * Opcode     | Mnemonic          | Stack     | Memory                                                |
             * ---------------------------------------------------------------------------------------------------|
             * 61 runSize | PUSH2 runSize     | r         |                                                       |
             * 3d         | RETURNDATASIZE    | 0 r       |                                                       |
             * 81         | DUP2              | r 0 r     |                                                       |
             * 60 offset  | PUSH1 offset      | o r 0 r   |                                                       |
             * 3d         | RETURNDATASIZE    | 0 o r 0 r |                                                       |
             * 39         | CODECOPY          | 0 r       | [0..runSize): runtime code                            |
             * f3         | RETURN            |           | [0..runSize): runtime code                            |
             * ---------------------------------------------------------------------------------------------------|
             * RUNTIME (98 bytes + extraLength)                                                                   |
             * ---------------------------------------------------------------------------------------------------|
             * Opcode   | Mnemonic       | Stack                    | Memory                                      |
             * ---------------------------------------------------------------------------------------------------|
             *                                                                                                    |
             * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 36       | CALLDATASIZE   | cds                      |                                             |
             * 3d       | RETURNDATASIZE | 0 cds                    |                                             |
             * 3d       | RETURNDATASIZE | 0 0 cds                  |                                             |
             * 37       | CALLDATACOPY   |                          | [0..cds): calldata                          |
             *                                                                                                    |
             * ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d       | RETURNDATASIZE | 0                        | [0..cds): calldata                          |
             * 3d       | RETURNDATASIZE | 0 0                      | [0..cds): calldata                          |
             * 3d       | RETURNDATASIZE | 0 0 0                    | [0..cds): calldata                          |
             * 3d       | RETURNDATASIZE | 0 0 0 0                  | [0..cds): calldata                          |
             * 61 extra | PUSH2 extra    | e 0 0 0 0                | [0..cds): calldata                          |
             *                                                                                                    |
             * ::: copy extra data to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 80       | DUP1           | e e 0 0 0 0              | [0..cds): calldata                          |
             * 60 0x35  | PUSH1 0x35     | 0x35 e e 0 0 0 0         | [0..cds): calldata                          |
             * 36       | CALLDATASIZE   | cds 0x35 e e 0 0 0 0     | [0..cds): calldata                          |
             * 39       | CODECOPY       | e 0 0 0 0                | [0..cds): calldata, [cds..cds+e): extraData |
             *                                                                                                    |
             * ::: delegate call to the implementation contract ::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 36       | CALLDATASIZE   | cds e 0 0 0 0            | [0..cds): calldata, [cds..cds+e): extraData |
             * 01       | ADD            | cds+e 0 0 0 0            | [0..cds): calldata, [cds..cds+e): extraData |
             * 3d       | RETURNDATASIZE | 0 cds+e 0 0 0 0          | [0..cds): calldata, [cds..cds+e): extraData |
             * 73 addr  | PUSH20 addr    | addr 0 cds+e 0 0 0 0     | [0..cds): calldata, [cds..cds+e): extraData |
             * 5a       | GAS            | gas addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
             * f4       | DELEGATECALL   | success 0 0              | [0..cds): calldata, [cds..cds+e): extraData |
             *                                                                                                    |
             * ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d       | RETURNDATASIZE | rds success 0 0          | [0..cds): calldata, [cds..cds+e): extraData |
             * 3d       | RETURNDATASIZE | rds rds success 0 0      | [0..cds): calldata, [cds..cds+e): extraData |
             * 93       | SWAP4          | 0 rds success 0 rds      | [0..cds): calldata, [cds..cds+e): extraData |
             * 80       | DUP1           | 0 0 rds success 0 rds    | [0..cds): calldata, [cds..cds+e): extraData |
             * 3e       | RETURNDATACOPY | success 0 rds            | [0..rds): returndata                        |
             *                                                                                                    |
             * 60 0x33  | PUSH1 0x33     | 0x33 success 0 rds       | [0..rds): returndata                        |
             * 57       | JUMPI          | 0 rds                    | [0..rds): returndata                        |
             *                                                                                                    |
             * ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * fd       | REVERT         |                          | [0..rds): returndata                        |
             *                                                                                                    |
             * ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b       | JUMPDEST       | 0 rds                    | [0..rds): returndata                        |
             * f3       | RETURN         |                          | [0..rds): returndata                        |
             * ---------------------------------------------------------------------------------------------------+
             */
            // Write the bytecode before the data.
            mstore(data, 0x5af43d3d93803e603357fd5bf3)
            // Write the address of the implementation.
            mstore(sub(data, 0x0d), implementation)
            mstore(
                sub(data, 0x21),
                or(
                    shl(0xd8, add(extraLength, 0x35)),
                    or(shl(0x48, extraLength), 0x6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d73)
                )
            )
            mstore(dataEnd, shl(0xf0, extraLength))

            // Create the instance.
            instance := create2(0, sub(data, 0x1f), add(extraLength, 0x3f), salt)

            // If `instance` is zero, revert.
            if iszero(instance) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Restore the overwritten memory surrounding `data`.
            mstore(dataEnd, mAfter1)
            mstore(data, dataLength)
            mstore(sub(data, 0x20), mBefore1)
            mstore(sub(data, 0x40), mBefore2)
        }
    }

    /**
     * @dev Returns the initialization code hash of the clone of `implementation`
     * using immutable arguments encoded in `data`.
     * Used for mining vanity addresses with create2crunch.
     * @param implementation The address of the implementation contract.
     * @param data The encoded immutable arguments.
     * @return hash The initialization code hash.
     */
    function initCodeHash(address implementation, bytes memory data) internal pure returns (bytes32 hash) {
        assembly {
            // Compute the boundaries of the data and cache the memory slots around it.
            let mBefore2 := mload(sub(data, 0x40))
            let mBefore1 := mload(sub(data, 0x20))
            let dataLength := mload(data)
            let dataEnd := add(add(data, 0x20), dataLength)
            let mAfter1 := mload(dataEnd)

            // +2 bytes for telling how much data there is appended to the call.
            let extraLength := add(dataLength, 2)
            // The `creationSize` is `extraLength + 63`
            // The `runSize` is `creationSize - 10`.

            // if `extraLength` is greater than `0xffca` revert as the `creationSize` would be greater than `0xffff`.
            if gt(extraLength, 0xffca) {
                // Store the function selector of `PackedDataTooBig()`.
                mstore(0x00, 0xc8c78139)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Write the bytecode before the data.
            mstore(data, 0x5af43d3d93803e603357fd5bf3)
            // Write the address of the implementation.
            mstore(sub(data, 0x0d), implementation)
            mstore(
                sub(data, 0x21),
                or(
                    shl(0xd8, add(extraLength, 0x35)),
                    or(shl(0x48, extraLength), 0x6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d73)
                )
            )
            mstore(dataEnd, shl(0xf0, extraLength))

            // Create the instance.
            hash := keccak256(sub(data, 0x1f), add(extraLength, 0x3f))

            // Restore the overwritten memory surrounding `data`.
            mstore(dataEnd, mAfter1)
            mstore(data, dataLength)
            mstore(sub(data, 0x20), mBefore1)
            mstore(sub(data, 0x40), mBefore2)
        }
    }

    /**
     * @dev Returns the address of the deterministic clone of
     * `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`.
     * @param implementation The address of the implementation.
     * @param data The immutable arguments of the implementation.
     * @param salt The salt used to compute the address.
     * @param deployer The address of the deployer.
     * @return predicted The predicted address.
     */
    function predictDeterministicAddress(address implementation, bytes memory data, bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        bytes32 hash = initCodeHash(implementation, data);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /**
     * @dev Returns the address when a contract with initialization code hash,
     * `hash`, is deployed with `salt`, by `deployer`.
     * @param hash The initialization code hash.
     * @param salt The salt used to compute the address.
     * @param deployer The address of the deployer.
     * @return predicted The predicted address.
     */
    function predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the boundaries of the data and cache the memory slots around it.
            let mBefore := mload(0x35)

            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, hash)
            mstore(0x01, shl(96, deployer))
            mstore(0x15, salt)
            predicted := keccak256(0x00, 0x55)

            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x35, mBefore)
        }
    }
}

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

pragma solidity 0.8.10;

import {Constants} from "./Constants.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {Encoded} from "./math/Encoded.sol";

/**
 * @title Liquidity Book Pair Parameter Helper Library
 * @author Trader Joe
 * @dev This library contains functions to get and set parameters of a pair
 * The parameters are stored in a single bytes32 variable in the following format:
 * [0 - 16[: base factor (16 bits)
 * [16 - 28[: filter period (12 bits)
 * [28 - 40[: decay period (12 bits)
 * [40 - 54[: reduction factor (14 bits)
 * [54 - 78[: variable fee control (24 bits)
 * [78 - 92[: protocol share (14 bits)
 * [92 - 112[: max volatility accumulator (20 bits)
 * [112 - 132[: volatility accumulator (20 bits)
 * [132 - 152[: volatility reference (20 bits)
 * [152 - 176[: index reference (24 bits)
 * [176 - 216[: time of last update (40 bits)
 * [216 - 232[: oracle index (16 bits)
 * [232 - 256[: active index (24 bits)
 */
library PairParameterHelper {
    using SafeCast for uint256;
    using Encoded for bytes32;

    error PairParametersHelper__InvalidParameter();

    uint256 internal constant OFFSET_BASE_FACTOR = 0;
    uint256 internal constant OFFSET_FILTER_PERIOD = 16;
    uint256 internal constant OFFSET_DECAY_PERIOD = 28;
    uint256 internal constant OFFSET_REDUCTION_FACTOR = 40;
    uint256 internal constant OFFSET_VAR_FEE_CONTROL = 54;
    uint256 internal constant OFFSET_PROTOCOL_SHARE = 78;
    uint256 internal constant OFFSET_MAX_VOL_ACC = 92;
    uint256 internal constant OFFSET_VOL_ACC = 112;
    uint256 internal constant OFFSET_VOL_REF = 132;
    uint256 internal constant OFFSET_ID_REF = 152;
    uint256 internal constant OFFSET_TIME_LAST_UPDATE = 176;
    uint256 internal constant OFFSET_ORACLE_ID = 216;
    uint256 internal constant OFFSET_ACTIVE_ID = 232;

    uint256 internal constant MASK_STATIC_PARAMETER = 0xffffffffffffffffffffffffffff;

    /**
     * @dev Get the base factor from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 16[: base factor (16 bits)
     * [16 - 256[: other parameters
     * @return baseFactor The base factor
     */
    function getBaseFactor(bytes32 params) internal pure returns (uint16 baseFactor) {
        baseFactor = params.decodeUint16(OFFSET_BASE_FACTOR);
    }

    /**
     * @dev Get the filter period from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 16[: other parameters
     * [16 - 28[: filter period (12 bits)
     * [28 - 256[: other parameters
     * @return filterPeriod The filter period
     */
    function getFilterPeriod(bytes32 params) internal pure returns (uint16 filterPeriod) {
        filterPeriod = params.decodeUint12(OFFSET_FILTER_PERIOD);
    }

    /**
     * @dev Get the decay period from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 28[: other parameters
     * [28 - 40[: decay period (12 bits)
     * [40 - 256[: other parameters
     * @return decayPeriod The decay period
     */
    function getDecayPeriod(bytes32 params) internal pure returns (uint16 decayPeriod) {
        decayPeriod = params.decodeUint12(OFFSET_DECAY_PERIOD);
    }

    /**
     * @dev Get the reduction factor from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 40[: other parameters
     * [40 - 54[: reduction factor (14 bits)
     * [54 - 256[: other parameters
     * @return reductionFactor The reduction factor
     */
    function getReductionFactor(bytes32 params) internal pure returns (uint16 reductionFactor) {
        reductionFactor = params.decodeUint14(OFFSET_REDUCTION_FACTOR);
    }

    /**
     * @dev Get the variable fee control from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 54[: other parameters
     * [54 - 78[: variable fee control (24 bits)
     * [78 - 256[: other parameters
     * @return variableFeeControl The variable fee control
     */
    function getVariableFeeControl(bytes32 params) internal pure returns (uint24 variableFeeControl) {
        variableFeeControl = params.decodeUint24(OFFSET_VAR_FEE_CONTROL);
    }

    /**
     * @dev Get the protocol share from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 78[: other parameters
     * [78 - 92[: protocol share (14 bits)
     * [92 - 256[: other parameters
     * @return protocolShare The protocol share
     */
    function getProtocolShare(bytes32 params) internal pure returns (uint16 protocolShare) {
        protocolShare = params.decodeUint14(OFFSET_PROTOCOL_SHARE);
    }

    /**
     * @dev Get the max volatility accumulator from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 92[: other parameters
     * [92 - 112[: max volatility accumulator (20 bits)
     * [112 - 256[: other parameters
     * @return maxVolatilityAccumulator The max volatility accumulator
     */
    function getMaxVolatilityAccumulator(bytes32 params) internal pure returns (uint24 maxVolatilityAccumulator) {
        maxVolatilityAccumulator = params.decodeUint20(OFFSET_MAX_VOL_ACC);
    }

    /**
     * @dev Get the volatility accumulator from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 112[: other parameters
     * [112 - 132[: volatility accumulator (20 bits)
     * [132 - 256[: other parameters
     * @return volatilityAccumulator The volatility accumulator
     */
    function getVolatilityAccumulator(bytes32 params) internal pure returns (uint24 volatilityAccumulator) {
        volatilityAccumulator = params.decodeUint20(OFFSET_VOL_ACC);
    }

    /**
     * @dev Get the volatility reference from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 132[: other parameters
     * [132 - 152[: volatility reference (20 bits)
     * [152 - 256[: other parameters
     * @return volatilityReference The volatility reference
     */
    function getVolatilityReference(bytes32 params) internal pure returns (uint24 volatilityReference) {
        volatilityReference = params.decodeUint20(OFFSET_VOL_REF);
    }

    /**
     * @dev Get the index reference from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 152[: other parameters
     * [152 - 176[: index reference (24 bits)
     * [176 - 256[: other parameters
     * @return idReference The index reference
     */
    function getIdReference(bytes32 params) internal pure returns (uint24 idReference) {
        idReference = params.decodeUint24(OFFSET_ID_REF);
    }

    /**
     * @dev Get the time of last update from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 176[: other parameters
     * [176 - 216[: time of last update (40 bits)
     * [216 - 256[: other parameters
     * @return timeOflastUpdate The time of last update
     */
    function getTimeOfLastUpdate(bytes32 params) internal pure returns (uint40 timeOflastUpdate) {
        timeOflastUpdate = params.decodeUint40(OFFSET_TIME_LAST_UPDATE);
    }

    /**
     * @dev Get the oracle id from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 216[: other parameters
     * [216 - 232[: oracle id (16 bits)
     * [232 - 256[: other parameters
     * @return oracleId The oracle id
     */
    function getOracleId(bytes32 params) internal pure returns (uint16 oracleId) {
        oracleId = params.decodeUint16(OFFSET_ORACLE_ID);
    }

    /**
     * @dev Get the active index from the encoded pair parameters
     * @param params The encoded pair parameters, as follows:
     * [0 - 232[: other parameters
     * [232 - 256[: active index (24 bits)
     * @return activeId The active index
     */
    function getActiveId(bytes32 params) internal pure returns (uint24 activeId) {
        activeId = params.decodeUint24(OFFSET_ACTIVE_ID);
    }

    /**
     * @dev Get the delta between the current active index and the cached active index
     * @param params The encoded pair parameters, as follows:
     * [0 - 232[: other parameters
     * [232 - 256[: active index (24 bits)
     * @param activeId The current active index
     * @return The delta
     */
    function getDeltaId(bytes32 params, uint24 activeId) internal pure returns (uint24) {
        uint24 id = getActiveId(params);
        unchecked {
            return activeId > id ? activeId - id : id - activeId;
        }
    }

    /**
     * @dev Calculates the base fee, with 18 decimals
     * @param params The encoded pair parameters
     * @param binStep The bin step (in basis points)
     * @return baseFee The base fee
     */
    function getBaseFee(bytes32 params, uint16 binStep) internal pure returns (uint256) {
        unchecked {
            // Base factor is in basis points, binStep is in basis points, so we multiply by 1e10
            return uint256(getBaseFactor(params)) * binStep * 1e10;
        }
    }

    /**
     * @dev Calculates the variable fee
     * @param params The encoded pair parameters
     * @param binStep The bin step (in basis points)
     * @return variableFee The variable fee
     */
    function getVariableFee(bytes32 params, uint16 binStep) internal pure returns (uint256 variableFee) {
        uint256 variableFeeControl = getVariableFeeControl(params);

        if (variableFeeControl != 0) {
            unchecked {
                // The volatility accumulator is in basis points, binStep is in basis points,
                // and the variable fee control is in basis points, so the result is in 100e18th
                uint256 prod = uint256(getVolatilityAccumulator(params)) * binStep;
                variableFee = (prod * prod * variableFeeControl + 99) / 100;
            }
        }
    }

    /**
     * @dev Calculates the total fee, which is the sum of the base fee and the variable fee
     * @param params The encoded pair parameters
     * @param binStep The bin step (in basis points)
     * @return totalFee The total fee
     */
    function getTotalFee(bytes32 params, uint16 binStep) internal pure returns (uint128) {
        unchecked {
            return (getBaseFee(params, binStep) + getVariableFee(params, binStep)).safe128();
        }
    }

    /**
     * @dev Set the oracle id in the encoded pair parameters
     * @param params The encoded pair parameters
     * @param oracleId The oracle id
     * @return The updated encoded pair parameters
     */
    function setOracleId(bytes32 params, uint16 oracleId) internal pure returns (bytes32) {
        return params.set(oracleId, Encoded.MASK_UINT16, OFFSET_ORACLE_ID);
    }

    /**
     * @dev Set the volatility reference in the encoded pair parameters
     * @param params The encoded pair parameters
     * @param volRef The volatility reference
     * @return The updated encoded pair parameters
     */
    function setVolatilityReference(bytes32 params, uint24 volRef) internal pure returns (bytes32) {
        if (volRef > Encoded.MASK_UINT20) revert PairParametersHelper__InvalidParameter();

        return params.set(volRef, Encoded.MASK_UINT20, OFFSET_VOL_REF);
    }

    /**
     * @dev Set the volatility accumulator in the encoded pair parameters
     * @param params The encoded pair parameters
     * @param volAcc The volatility accumulator
     * @return The updated encoded pair parameters
     */
    function setVolatilityAccumulator(bytes32 params, uint24 volAcc) internal pure returns (bytes32) {
        if (volAcc > Encoded.MASK_UINT20) revert PairParametersHelper__InvalidParameter();

        return params.set(volAcc, Encoded.MASK_UINT20, OFFSET_VOL_ACC);
    }

    /**
     * @dev Set the active id in the encoded pair parameters
     * @param params The encoded pair parameters
     * @param activeId The active id
     * @return newParams The updated encoded pair parameters
     */
    function setActiveId(bytes32 params, uint24 activeId) internal pure returns (bytes32 newParams) {
        return params.set(activeId, Encoded.MASK_UINT24, OFFSET_ACTIVE_ID);
    }

    /**
     * @dev Sets the static fee parameters in the encoded pair parameters
     * @param params The encoded pair parameters
     * @param baseFactor The base factor
     * @param filterPeriod The filter period
     * @param decayPeriod The decay period
     * @param reductionFactor The reduction factor
     * @param variableFeeControl The variable fee control
     * @param protocolShare The protocol share
     * @param maxVolatilityAccumulator The max volatility accumulator
     * @return newParams The updated encoded pair parameters
     */
    function setStaticFeeParameters(
        bytes32 params,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator
    ) internal pure returns (bytes32 newParams) {
        if (
            filterPeriod > decayPeriod || decayPeriod > Encoded.MASK_UINT12
                || reductionFactor > Constants.BASIS_POINT_MAX || protocolShare > Constants.MAX_PROTOCOL_SHARE
                || maxVolatilityAccumulator > Encoded.MASK_UINT20
        ) revert PairParametersHelper__InvalidParameter();

        newParams = newParams.set(baseFactor, Encoded.MASK_UINT16, OFFSET_BASE_FACTOR);
        newParams = newParams.set(filterPeriod, Encoded.MASK_UINT12, OFFSET_FILTER_PERIOD);
        newParams = newParams.set(decayPeriod, Encoded.MASK_UINT12, OFFSET_DECAY_PERIOD);
        newParams = newParams.set(reductionFactor, Encoded.MASK_UINT14, OFFSET_REDUCTION_FACTOR);
        newParams = newParams.set(variableFeeControl, Encoded.MASK_UINT24, OFFSET_VAR_FEE_CONTROL);
        newParams = newParams.set(protocolShare, Encoded.MASK_UINT14, OFFSET_PROTOCOL_SHARE);
        newParams = newParams.set(maxVolatilityAccumulator, Encoded.MASK_UINT20, OFFSET_MAX_VOL_ACC);

        return params.set(uint256(newParams), MASK_STATIC_PARAMETER, 0);
    }

    /**
     * @dev Updates the index reference in the encoded pair parameters
     * @param params The encoded pair parameters
     * @return newParams The updated encoded pair parameters
     */
    function updateIdReference(bytes32 params) internal pure returns (bytes32 newParams) {
        uint24 activeId = getActiveId(params);
        return params.set(activeId, Encoded.MASK_UINT24, OFFSET_ID_REF);
    }

    /**
     * @dev Updates the time of last update in the encoded pair parameters
     * @param params The encoded pair parameters
     * @return newParams The updated encoded pair parameters
     */
    function updateTimeOfLastUpdate(bytes32 params) internal view returns (bytes32 newParams) {
        uint40 currentTime = block.timestamp.safe40();
        return params.set(currentTime, Encoded.MASK_UINT40, OFFSET_TIME_LAST_UPDATE);
    }

    /**
     * @dev Updates the volatility reference in the encoded pair parameters
     * @param params The encoded pair parameters
     * @return The updated encoded pair parameters
     */
    function updateVolatilityReference(bytes32 params) internal pure returns (bytes32) {
        uint256 volAcc = getVolatilityAccumulator(params);
        uint256 reductionFactor = getReductionFactor(params);

        uint24 volRef;
        unchecked {
            volRef = uint24(volAcc * reductionFactor / Constants.BASIS_POINT_MAX);
        }

        return setVolatilityReference(params, volRef);
    }

    /**
     * @dev Updates the volatility accumulator in the encoded pair parameters
     * @param params The encoded pair parameters
     * @param activeId The active id
     * @return The updated encoded pair parameters
     */
    function updateVolatilityAccumulator(bytes32 params, uint24 activeId) internal pure returns (bytes32) {
        uint256 idReference = getIdReference(params);

        uint256 deltaId;
        uint256 volAcc;

        unchecked {
            deltaId = activeId > idReference ? activeId - idReference : idReference - activeId;
            volAcc = (uint256(getVolatilityReference(params)) + deltaId * Constants.BASIS_POINT_MAX);
        }

        uint256 maxVolAcc = getMaxVolatilityAccumulator(params);

        volAcc = volAcc > maxVolAcc ? maxVolAcc : volAcc;

        return setVolatilityAccumulator(params, uint24(volAcc));
    }

    /**
     * @dev Updates the volatility reference and the volatility accumulator in the encoded pair parameters
     * @param params The encoded pair parameters
     * @return The updated encoded pair parameters
     */
    function updateReferences(bytes32 params) internal view returns (bytes32) {
        uint256 dt = block.timestamp - getTimeOfLastUpdate(params);

        if (dt >= getFilterPeriod(params)) {
            params = updateIdReference(params);
            params = dt < getDecayPeriod(params) ? updateVolatilityReference(params) : setVolatilityReference(params, 0);
        }

        return updateTimeOfLastUpdate(params);
    }

    /**
     * @dev Updates the volatility reference and the volatility accumulator in the encoded pair parameters
     * @param params The encoded pair parameters
     * @param activeId The active id
     * @return The updated encoded pair parameters
     */
    function updateVolatilityParameters(bytes32 params, uint24 activeId) internal view returns (bytes32) {
        params = updateReferences(params);
        return updateVolatilityAccumulator(params, activeId);
    }
}

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

pragma solidity 0.8.10;

import {IPendingOwnable} from "../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 sets 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));
    }

    /**
     * @dev 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);
    }

    /**
     * @dev 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_);
    }
}

File 14 of 19 : PriceHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import {Uint128x128Math} from "./math/Uint128x128Math.sol";
import {Uint256x256Math} from "./math/Uint256x256Math.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {Constants} from "./Constants.sol";

/**
 * @title Liquidity Book Price Helper Library
 * @author Trader Joe
 * @notice This library contains functions to calculate prices
 */
library PriceHelper {
    using Uint128x128Math for uint256;
    using Uint256x256Math for uint256;
    using SafeCast for uint256;

    int256 private constant REAL_ID_SHIFT = 1 << 23;

    /**
     * @dev Calculates the price from the id and the bin step
     * @param id The id
     * @param binStep The bin step
     * @return price The price as a 128.128-binary fixed-point number
     */
    function getPriceFromId(uint24 id, uint16 binStep) internal pure returns (uint256 price) {
        uint256 base = getBase(binStep);
        int256 exponent = getExponent(id);

        price = base.pow(exponent);
    }

    /**
     * @dev Calculates the id from the price and the bin step
     * @param price The price as a 128.128-binary fixed-point number
     * @param binStep The bin step
     * @return id The id
     */
    function getIdFromPrice(uint256 price, uint16 binStep) internal pure returns (uint24 id) {
        uint256 base = getBase(binStep);
        int256 realId = price.log2() / base.log2();

        unchecked {
            id = uint256(REAL_ID_SHIFT + realId).safe24();
        }
    }

    /**
     * @dev Calculates the base from the bin step, which is `1 + binStep / BASIS_POINT_MAX`
     * @param binStep The bin step
     * @return base The base
     */
    function getBase(uint16 binStep) internal pure returns (uint256) {
        unchecked {
            return Constants.SCALE + (uint256(binStep) << Constants.SCALE_OFFSET) / Constants.BASIS_POINT_MAX;
        }
    }

    /**
     * @dev Calculates the exponent from the id, which is `id - REAL_ID_SHIFT`
     * @param id The id
     * @return exponent The exponent
     */
    function getExponent(uint24 id) internal pure returns (int256) {
        unchecked {
            return int256(uint256(id)) - REAL_ID_SHIFT;
        }
    }

    /**
     * @dev Converts a price with 18 decimals to a 128.128-binary fixed-point number
     * @param price The price with 18 decimals
     * @return price128x128 The 128.128-binary fixed-point number
     */
    function convertDecimalPriceTo128x128(uint256 price) internal pure returns (uint256) {
        return price.shiftDivRoundDown(Constants.SCALE_OFFSET, Constants.PRECISION);
    }

    /**
     * @dev Converts a 128.128-binary fixed-point number to a price with 18 decimals
     * @param price128x128 The 128.128-binary fixed-point number
     * @return price The price with 18 decimals
     */
    function convert128x128PriceToDecimal(uint256 price128x128) internal pure returns (uint256) {
        return price128x128.mulShiftRoundDown(Constants.PRECISION, Constants.SCALE_OFFSET);
    }
}

File 15 of 19 : BitMath.sol
// 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 {
    /**
     * @dev 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;
        }
    }

    /**
     * @dev 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;
        }
    }

    /**
     * @dev Returns the index of the most significant bit of x
     * This function returns 0 if x is 0
     * @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) {
        assembly {
            if gt(x, 0xffffffffffffffffffffffffffffffff) {
                x := shr(128, x)
                msb := 128
            }
            if gt(x, 0xffffffffffffffff) {
                x := shr(64, x)
                msb := add(msb, 64)
            }
            if gt(x, 0xffffffff) {
                x := shr(32, x)
                msb := add(msb, 32)
            }
            if gt(x, 0xffff) {
                x := shr(16, x)
                msb := add(msb, 16)
            }
            if gt(x, 0xff) {
                x := shr(8, x)
                msb := add(msb, 8)
            }
            if gt(x, 0xf) {
                x := shr(4, x)
                msb := add(msb, 4)
            }
            if gt(x, 0x3) {
                x := shr(2, x)
                msb := add(msb, 2)
            }
            if gt(x, 0x1) { msb := add(msb, 1) }
        }
    }

    /**
     * @dev Returns the index of the least significant bit of x
     * This function returns 255 if x is 0
     * @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) {
        assembly {
            let sx := shl(128, x)
            if iszero(iszero(sx)) {
                lsb := 128
                x := sx
            }
            sx := shl(64, x)
            if iszero(iszero(sx)) {
                x := sx
                lsb := add(lsb, 64)
            }
            sx := shl(32, x)
            if iszero(iszero(sx)) {
                x := sx
                lsb := add(lsb, 32)
            }
            sx := shl(16, x)
            if iszero(iszero(sx)) {
                x := sx
                lsb := add(lsb, 16)
            }
            sx := shl(8, x)
            if iszero(iszero(sx)) {
                x := sx
                lsb := add(lsb, 8)
            }
            sx := shl(4, x)
            if iszero(iszero(sx)) {
                x := sx
                lsb := add(lsb, 4)
            }
            sx := shl(2, x)
            if iszero(iszero(sx)) {
                x := sx
                lsb := add(lsb, 2)
            }
            if iszero(iszero(shl(1, x))) { lsb := add(lsb, 1) }

            lsb := sub(255, lsb)
        }
    }
}

File 16 of 19 : Encoded.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/**
 * @title Liquidity Book Encoded Library
 * @author Trader Joe
 * @notice Helper contract used for decoding bytes32 sample
 */
library Encoded {
    uint256 internal constant MASK_UINT1 = 0x1;
    uint256 internal constant MASK_UINT8 = 0xff;
    uint256 internal constant MASK_UINT12 = 0xfff;
    uint256 internal constant MASK_UINT14 = 0x3fff;
    uint256 internal constant MASK_UINT16 = 0xffff;
    uint256 internal constant MASK_UINT20 = 0xfffff;
    uint256 internal constant MASK_UINT24 = 0xffffff;
    uint256 internal constant MASK_UINT40 = 0xffffffffff;
    uint256 internal constant MASK_UINT64 = 0xffffffffffffffff;
    uint256 internal constant MASK_UINT128 = 0xffffffffffffffffffffffffffffffff;

    /**
     * @notice Internal function to set a value in an encoded bytes32 using a mask and offset
     * @dev This function can overflow
     * @param encoded The previous encoded value
     * @param value The value to encode
     * @param mask The mask
     * @param offset The offset
     * @return newEncoded The new encoded value
     */
    function set(bytes32 encoded, uint256 value, uint256 mask, uint256 offset)
        internal
        pure
        returns (bytes32 newEncoded)
    {
        assembly {
            newEncoded := and(encoded, not(shl(offset, mask)))
            newEncoded := or(newEncoded, shl(offset, and(value, mask)))
        }
    }

    /**
     * @notice Internal function to set a bool in an encoded bytes32 using an offset
     * @dev This function can overflow
     * @param encoded The previous encoded value
     * @param boolean The bool to encode
     * @param offset The offset
     * @return newEncoded The new encoded value
     */
    function setBool(bytes32 encoded, bool boolean, uint256 offset) internal pure returns (bytes32 newEncoded) {
        return set(encoded, boolean ? 1 : 0, MASK_UINT1, offset);
    }

    /**
     * @notice Internal function to decode a bytes32 sample using a mask and offset
     * @dev This function can overflow
     * @param encoded The encoded value
     * @param mask The mask
     * @param offset The offset
     * @return value The decoded value
     */
    function decode(bytes32 encoded, uint256 mask, uint256 offset) internal pure returns (uint256 value) {
        assembly {
            value := and(shr(offset, encoded), mask)
        }
    }

    /**
     * @notice Internal function to decode a bytes32 sample into a bool using an offset
     * @dev This function can overflow
     * @param encoded The encoded value
     * @param offset The offset
     * @return boolean The decoded value as a bool
     */
    function decodeBool(bytes32 encoded, uint256 offset) internal pure returns (bool boolean) {
        assembly {
            boolean := and(shr(offset, encoded), MASK_UINT1)
        }
    }

    /**
     * @notice Internal function to decode a bytes32 sample into a uint8 using an offset
     * @dev This function can overflow
     * @param encoded The encoded value
     * @param offset The offset
     * @return value The decoded value
     */
    function decodeUint8(bytes32 encoded, uint256 offset) internal pure returns (uint8 value) {
        assembly {
            value := and(shr(offset, encoded), MASK_UINT8)
        }
    }

    /**
     * @notice Internal function to decode a bytes32 sample into a uint12 using an offset
     * @dev This function can overflow
     * @param encoded The encoded value
     * @param offset The offset
     * @return value The decoded value as a uint16, since uint12 is not supported
     */
    function decodeUint12(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) {
        assembly {
            value := and(shr(offset, encoded), MASK_UINT12)
        }
    }

    /**
     * @notice Internal function to decode a bytes32 sample into a uint14 using an offset
     * @dev This function can overflow
     * @param encoded The encoded value
     * @param offset The offset
     * @return value The decoded value as a uint16, since uint14 is not supported
     */
    function decodeUint14(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) {
        assembly {
            value := and(shr(offset, encoded), MASK_UINT14)
        }
    }

    /**
     * @notice Internal function to decode a bytes32 sample into a uint16 using an offset
     * @dev This function can overflow
     * @param encoded The encoded value
     * @param offset The offset
     * @return value The decoded value
     */
    function decodeUint16(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) {
        assembly {
            value := and(shr(offset, encoded), MASK_UINT16)
        }
    }

    /**
     * @notice Internal function to decode a bytes32 sample into a uint20 using an offset
     * @dev This function can overflow
     * @param encoded The encoded value
     * @param offset The offset
     * @return value The decoded value as a uint24, since uint20 is not supported
     */
    function decodeUint20(bytes32 encoded, uint256 offset) internal pure returns (uint24 value) {
        assembly {
            value := and(shr(offset, encoded), MASK_UINT20)
        }
    }

    /**
     * @notice Internal function to decode a bytes32 sample into a uint24 using an offset
     * @dev This function can overflow
     * @param encoded The encoded value
     * @param offset The offset
     * @return value The decoded value
     */
    function decodeUint24(bytes32 encoded, uint256 offset) internal pure returns (uint24 value) {
        assembly {
            value := and(shr(offset, encoded), MASK_UINT24)
        }
    }

    /**
     * @notice Internal function to decode a bytes32 sample into a uint40 using an offset
     * @dev This function can overflow
     * @param encoded The encoded value
     * @param offset The offset
     * @return value The decoded value
     */
    function decodeUint40(bytes32 encoded, uint256 offset) internal pure returns (uint40 value) {
        assembly {
            value := and(shr(offset, encoded), MASK_UINT40)
        }
    }

    /**
     * @notice Internal function to decode a bytes32 sample into a uint64 using an offset
     * @dev This function can overflow
     * @param encoded The encoded value
     * @param offset The offset
     * @return value The decoded value
     */
    function decodeUint64(bytes32 encoded, uint256 offset) internal pure returns (uint64 value) {
        assembly {
            value := and(shr(offset, encoded), MASK_UINT64)
        }
    }

    /**
     * @notice Internal function to decode a bytes32 sample into a uint128 using an offset
     * @dev This function can overflow
     * @param encoded The encoded value
     * @param offset The offset
     * @return value The decoded value
     */
    function decodeUint128(bytes32 encoded, uint256 offset) internal pure returns (uint128 value) {
        assembly {
            value := and(shr(offset, encoded), MASK_UINT128)
        }
    }
}

File 17 of 19 : SafeCast.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/**
 * @title Liquidity Book Safe Cast Library
 * @author Trader Joe
 * @notice This library contains functions to safely cast uint256 to different uint types.
 */
library SafeCast {
    error SafeCast__Exceeds248Bits();
    error SafeCast__Exceeds240Bits();
    error SafeCast__Exceeds232Bits();
    error SafeCast__Exceeds224Bits();
    error SafeCast__Exceeds216Bits();
    error SafeCast__Exceeds208Bits();
    error SafeCast__Exceeds200Bits();
    error SafeCast__Exceeds192Bits();
    error SafeCast__Exceeds184Bits();
    error SafeCast__Exceeds176Bits();
    error SafeCast__Exceeds168Bits();
    error SafeCast__Exceeds160Bits();
    error SafeCast__Exceeds152Bits();
    error SafeCast__Exceeds144Bits();
    error SafeCast__Exceeds136Bits();
    error SafeCast__Exceeds128Bits();
    error SafeCast__Exceeds120Bits();
    error SafeCast__Exceeds112Bits();
    error SafeCast__Exceeds104Bits();
    error SafeCast__Exceeds96Bits();
    error SafeCast__Exceeds88Bits();
    error SafeCast__Exceeds80Bits();
    error SafeCast__Exceeds72Bits();
    error SafeCast__Exceeds64Bits();
    error SafeCast__Exceeds56Bits();
    error SafeCast__Exceeds48Bits();
    error SafeCast__Exceeds40Bits();
    error SafeCast__Exceeds32Bits();
    error SafeCast__Exceeds24Bits();
    error SafeCast__Exceeds16Bits();
    error SafeCast__Exceeds8Bits();

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }

    /**
     * @dev 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();
    }
}

File 18 of 19 : Uint128x128Math.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import {Constants} from "../Constants.sol";
import {BitMath} from "./BitMath.sol";

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

    error Uint128x128Math__LogUnderflow();
    error Uint128x128Math__PowUnderflow(uint256 x, int256 y);

    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 Uint128x128Math__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^21; 2^21[
     */
    function pow(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 squared := x
                if gt(x, 0xffffffffffffffffffffffffffffffff) {
                    squared := div(not(0), squared)
                    invert := iszero(invert)
                }

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

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

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

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

pragma solidity 0.8.10;

/**
 * @title Liquidity Book Uint256x256 Math Library
 * @author Trader Joe
 * @notice Helper contract used for full precision calculations
 */
library Uint256x256Math {
    error Uint256x256Math__MulShiftOverflow();
    error Uint256x256Math__MulDivOverflow();

    /**
     * @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 ceil(x*y/denominator) 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 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 mulDivRoundUp(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        result = mulDivRoundDown(x, y, denominator);
        if (mulmod(x, y, denominator) != 0) result += 1;
    }

    /**
     * @notice Calculates floor(x * y / 2**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, uint8 offset) internal pure returns (uint256 result) {
        (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 Uint256x256Math__MulShiftOverflow();

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

    /**
     * @notice Calculates floor(x * y / 2**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 mulShiftRoundUp(uint256 x, uint256 y, uint8 offset) internal pure returns (uint256 result) {
        result = mulShiftRoundDown(x, y, offset);
        if (mulmod(x, y, 1 << offset) != 0) result += 1;
    }

    /**
     * @notice Calculates floor(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, uint8 offset, uint256 denominator) internal pure returns (uint256 result) {
        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 ceil(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, uint8 offset, uint256 denominator) internal pure returns (uint256 result) {
        result = shiftDivRoundDown(x, offset, denominator);
        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 Uint256x256Math__MulDivOverflow();

            // 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;
            }
        }
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "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":[],"name":"LBFactory__AddressZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBFactory__BinStepHasNoPreset","type":"error"},{"inputs":[{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBFactory__BinStepTooLow","type":"error"},{"inputs":[{"internalType":"uint256","name":"fees","type":"uint256"},{"internalType":"uint256","name":"maxFees","type":"uint256"}],"name":"LBFactory__FlashLoanFeeAboveMax","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":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBFactory__LBPairDoesNotExist","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":"address","name":"user","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBFactory__PresetIsLockedForUsers","type":"error"},{"inputs":[],"name":"LBFactory__PresetOpenStateIsAlreadyInTheSameState","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":"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":[],"name":"PairParametersHelper__InvalidParameter","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":[],"name":"SafeCast__Exceeds16Bits","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"int256","name":"y","type":"int256"}],"name":"Uint128x128Math__PowUnderflow","type":"error"},{"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"},{"indexed":true,"internalType":"bool","name":"isOpen","type":"bool"}],"name":"PresetOpenStateChanged","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":"maxVolatilityAccumulator","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":[{"internalType":"contract IERC20","name":"quoteAsset","type":"address"}],"name":"addQuoteAsset","outputs":[],"stateMutability":"nonpayable","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":"pair","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"pair","type":"address"}],"name":"forceDecay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllBinSteps","outputs":[{"internalType":"uint256[]","name":"binStepWithPreset","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":[],"name":"getFeeRecipient","outputs":[{"internalType":"address","name":"feeRecipient","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFlashLoanFee","outputs":[{"internalType":"uint256","name":"flashLoanFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getLBPairAtIndex","outputs":[{"internalType":"contract ILBPair","name":"lbPair","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLBPairImplementation","outputs":[{"internalType":"address","name":"lbPairImplementation","type":"address"}],"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":"lbPairInformation","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxFlashLoanFee","outputs":[{"internalType":"uint256","name":"maxFee","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getMinBinStep","outputs":[{"internalType":"uint256","name":"minBinStep","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getNumberOfLBPairs","outputs":[{"internalType":"uint256","name":"lbPairNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumberOfQuoteAssets","outputs":[{"internalType":"uint256","name":"numberOfQuoteAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOpenBinSteps","outputs":[{"internalType":"uint256[]","name":"openBinStep","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"binStep","type":"uint256"}],"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":"maxVolatilityAccumulator","type":"uint256"},{"internalType":"bool","name":"isOpen","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getQuoteAssetAtIndex","outputs":[{"internalType":"contract IERC20","name":"asset","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"isQuoteAsset","outputs":[{"internalType":"bool","name":"isQuote","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":"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":"maxVolatilityAccumulator","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":"uint16","name":"binStep","type":"uint16"},{"internalType":"bool","name":"ignored","type":"bool"}],"name":"setLBPairIgnored","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newLBPairImplementation","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":"maxVolatilityAccumulator","type":"uint24"},{"internalType":"bool","name":"isOpen","type":"bool"}],"name":"setPreset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"binStep","type":"uint16"},{"internalType":"bool","name":"isOpen","type":"bool"}],"name":"setPresetOpenState","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b5060405162002b9b38038062002b9b8339810160408190526200003491620001f4565b6200003f33620000d1565b67016345785d8a00008111156200007f57604051635e8988c160e01b81526004810182905267016345785d8a000060248201526044015b60405180910390fd5b6200008a826200012b565b60038190556040805160008152602081018390527f5c34e91c94c78b662a45d0bd4a25a4e32c584c54a45a76e4a4d43be27ba40e50910160405180910390a1505062000230565b600080546001600160a01b038381166001600160a01b031980841682178555600180549091169055604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381166200015357604051632573cfb960e21b815260040160405180910390fd5b6002546001600160a01b039081169082168114156200019557600254604051634fcea97160e01b81526001600160a01b03909116600482015260240162000076565b600280546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f15d80a013f22151bc7246e3bc132e12828cde19de98870475e3fa70840152721910160405180910390a15050565b600080604083850312156200020857600080fd5b82516001600160a01b03811681146200022057600080fd5b6020939093015192949293505050565b61295b80620002406000396000f3fe608060405234801561001057600080fd5b506004361061020b5760003560e01c8063704037bd1161012a578063b0384781116100bd578063e30c39781161008c578063e92d0d5d11610071578063e92d0d5d14610490578063f9dca989146104a3578063fd90c2be146104ab57600080fd5b8063e30c39781461046c578063e74b981b1461047d57600080fd5b8063b038478114610420578063c42069ec14610433578063ddbfd94114610446578063e203a31f1461045957600080fd5b80638ce9aa1c116100f95780638ce9aa1c146103a05780638da5cb5b146103ae578063aabc4b3c146103bf578063af3710651461040f57600080fd5b8063704037bd1461035d578063715018a61461037d5780637daf5d661461038557806380c5061e1461039857600080fd5b80634e937c3a116101a25780636622e0d7116101715780636622e0d71461031b57806367ab8a4e1461033b57806369d56ea314610343578063701ab8c11461035657600080fd5b80634e937c3a146102db5780635a440923146102ed5780635b35875c14610300578063659ac74b1461030857600080fd5b8063379ee803116101de578063379ee803146102915780633c78a941146102a45780634ccb20c0146102b75780634cd161d3146102c857600080fd5b80630282c9c1146102105780630752092b1461022e578063093ff76914610259578063277218421461026e575b600080fd5b6102186104b3565b6040516102259190612415565b60405180910390f35b61024161023c366004612459565b61058d565b6040516001600160a01b039091168152602001610225565b61026c6102673660046124ac565b6105a0565b005b61028161027c36600461256a565b6106c9565b6040519015158152602001610225565b61026c61029f366004612597565b6106d6565b61026c6102b236600461256a565b610815565b6002546001600160a01b0316610241565b61026c6102d636600461263f565b610896565b6005545b604051908152602001610225565b61026c6102fb36600461256a565b610985565b610218610a1a565b610241610316366004612672565b610a2b565b61032e6103293660046126ca565b610f8f565b6040516102259190612703565b61026c611127565b61026c610351366004612777565b611187565b60016102df565b61037061036b3660046127c4565b611335565b6040516102259190612805565b61026c61136c565b610241610393366004612459565b6113a1565b6102df6113d1565b67016345785d8a00006102df565b6000546001600160a01b0316610241565b6103d26103cd366004612459565b6113dd565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c0830152151560e082015261010001610225565b6004546001600160a01b0316610241565b61026c61042e36600461256a565b61149e565b61026c61044136600461256a565b611603565b61026c61045436600461256a565b61168b565b61026c610467366004612841565b611720565b6001546001600160a01b0316610241565b61026c61048b36600461256a565b6117af565b61026c61049e366004612459565b6117e3565b61026c6118aa565b6003546102df565b606060006104c160076118e9565b90508015610589578067ffffffffffffffff8111156104e2576104e261285c565b60405190808252806020026020018201604052801561050b578160200160208202803683370190505b5091506000805b8281101561057a576000806105286007846118f4565b909250905061053681611910565b15610567578186858151811061054e5761054e612872565b6020908102919091010152836105638161289e565b9450505b5050806105739061289e565b9050610512565b5081811015610587578083525b505b5090565b600061059a600a8361191c565b92915050565b6000546001600160a01b031633146105cb57604051639f216c1360e01b815260040160405180910390fd5b60006105dc8b8b8b61ffff1661192f565b6020015190506001600160a01b03811661062b5760405163b65ee95360e01b81526001600160a01b03808d1660048301528b16602482015261ffff8a1660448201526064015b60405180910390fd5b604051633329c28d60e11b815261ffff808a16600483015280891660248301528088166044830152808716606483015262ffffff808716608484015290851660a4830152831660c48201526001600160a01b03821690636653851a9060e401600060405180830381600087803b1580156106a457600080fd5b505af11580156106b8573d6000803e3d6000fd5b505050505050505050505050505050565b600061059a600a836119d9565b6000546001600160a01b0316331461070157604051639f216c1360e01b815260040160405180910390fd5b60018961ffff16101561072d57604051634f958e7160e01b815261ffff8a166004820152602401610622565b600061073f818a8a8a8a8a8a8a6119fb565b905081156107575761075481600160ff611afb565b90505b610767600761ffff8c1683611b22565b506040805161ffff8b811682528a8116602083015289811682840152888116606083015262ffffff888116608084015287821660a0840152861660c08301529151918c16917f839844a256a87f87c9c835117d9a1c40be013954064c937072acb32d36db6a289181900360e00190a26040518215159061ffff8c16907f58a8b6a02b964cca2712e5a71d7b0d564a56b4a0f573b4c47f389341ade14cfd90600090a350505050505050505050565b6000546001600160a01b0316331461084057604051639f216c1360e01b815260040160405180910390fd5b806001600160a01b031663d3b9fbe46040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561087b57600080fd5b505af115801561088f573d6000803e3d6000fd5b5050505050565b6000546001600160a01b031633146108c157604051639f216c1360e01b815260040160405180910390fd5b6108d0600761ffff8416611b2f565b6108f357604051637d9160bf60e11b815261ffff83166004820152602401610622565b6000610904600761ffff8516611b3b565b905081151560ff82901c1515141561092f576040516311be38db60e11b815260040160405180910390fd5b61094c61ffff8416610943838560ff611afb565b60079190611b22565b506040518215159061ffff8516907f58a8b6a02b964cca2712e5a71d7b0d564a56b4a0f573b4c47f389341ade14cfd90600090a3505050565b6000546001600160a01b031633146109b057604051639f216c1360e01b815260040160405180910390fd5b6109bb600a82611b47565b6109e3576040516303ce0ad960e01b81526001600160a01b0382166004820152602401610622565b6040516001600160a01b038216907f84cc2115995684dcb0cd3d3a9565e3d32f075de81db70c8dc3a719b2a47af67e90600090a250565b6060610a266007611b5c565b905090565b6000610a3c600761ffff8416611b2f565b610a5f57604051637d9160bf60e11b815261ffff83166004820152602401610622565b6000610a70600761ffff8516611b3b565b90506000610a866000546001600160a01b031690565b6001600160a01b0316336001600160a01b0316149050610aa582611910565b158015610ab0575080155b15610ada576040516304fc2fe760e11b815233600482015261ffff85166024820152604401610622565b610ae5600a876119d9565b610b0d57604051638e888ef360e01b81526001600160a01b0387166004820152602401610622565b856001600160a01b0316876001600160a01b03161415610b4b57604051632f9b185360e01b81526001600160a01b0388166004820152602401610622565b610b558585611b69565b50600080610b638989611bad565b90925090506001600160a01b038216610b8f57604051632573cfb960e21b815260040160405180910390fd5b6001600160a01b0382811660009081526006602090815260408083208585168452825280832061ffff8b1684529091529020546201000090041615610c045760405163cb27a43560e01b81526001600160a01b03808b1660048301528916602482015261ffff87166044820152606401610622565b6004546001600160a01b031680610c2e576040516328b4fcf960e21b815260040160405180910390fd5b6040516bffffffffffffffffffffffff1960608c811b821660208401528b901b1660348201527fffff00000000000000000000000000000000000000000000000000000000000060f089901b166048820152610cdb908290604a0160408051601f198184030181528282526001600160a01b03808916602085015287169183019190915261ffff8b1660608301529060800160405160208183030381529060405280519060200120611bd6565b955050846001600160a01b03166347973bff610cf686611c91565b610cff87611c9d565b610d0888611cad565b610d1189611cbd565b610d1a8a611ccd565b610d238b611cde565b610d2c8c611cee565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e08a901b16815261ffff978816600482015295871660248701529386166044860152918516606485015262ffffff9081166084850152931660a4830152821660c4820152908a1660e482015261010401600060405180830381600087803b158015610dbb57600080fd5b505af1158015610dcf573d6000803e3d6000fd5b50506040805160808101825261ffff808b168083526001600160a01b03808c1660208086018281528c15158789019081526000606089018181528e8716808352600686528b83208f89168085529087528c84208a855287528c84209b518c549651955193511515600160b81b0260ff60b81b19941515600160b01b02949094167fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff96909a1662010000027fffffffffffffffffffff000000000000000000000000000000000000000000009097169b169a909a179490941792909216959095171790965560058054600181019091557f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b031916909217909155938152600c84528481209281529190925291909120610f1393509150611cff565b508561ffff16886001600160a01b03168a6001600160a01b03167f2c8d104b27c6b7f4492017a6f5cf3803043688934ebcaa6a03540beeaf976aff886001600580549050610f6191906128b9565b604080516001600160a01b03909316835260208301919091520160405180910390a450505050949350505050565b6060600080610f9e8585611bad565b6001600160a01b038083166000908152600c602090815260408083209385168352929052908120929450909250610fd482611d0b565b9050801561111d578067ffffffffffffffff811115610ff557610ff561285c565b60405190808252806020026020018201604052801561104757816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816110135790505b506001600160a01b03808616600090815260066020908152604080832093881683529290529081209196505b8281101561111a57600061108f61108a868461191c565b611d15565b6040805160808101825261ffff831680825260008181526020888152848220546001600160a01b03620100008204168286015260ff600160b01b8204811615159686019690965292909152879052600160b81b90049091161515606082015289519192509089908490811061110657611106612872565b602090810291909101015250600101611073565b50505b5050505092915050565b6000546001600160a01b0316331461115257604051639f216c1360e01b815260040160405180910390fd5b6001546001600160a01b031661117b5760405163ecfad6bf60e01b815260040160405180910390fd5b6111856000611d3f565b565b6000546001600160a01b031633146111b257604051639f216c1360e01b815260040160405180910390fd5b6000806111bf8686611bad565b6001600160a01b0380831660009081526006602090815260408083208486168452825280832061ffff808c1685529083529281902081516080810183529054938416815262010000840490941691840182905260ff600160b01b84048116151591850191909152600160b81b90920490911615156060830152929450909250906112795760405163102a919160e21b81526001600160a01b0380891660048301528716602482015261ffff86166044820152606401610622565b8315158160600151151514156112a157604051626ee66560e11b815260040160405180910390fd5b6001600160a01b0380841660009081526006602090815260408083208685168452825280832061ffff8a1684528252918290208054881515600160b81b0260ff60b81b1990911617905583015190519116907f44cf35361c9ff3c8c1397ec6410d5495cc481feaef35c9af11da1a637107de4f9061132490871515815260200190565b60405180910390a250505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915261136484848461192f565b949350505050565b6000546001600160a01b0316331461139757604051639f216c1360e01b815260040160405180910390fd5b6111856000611d89565b6000600582815481106113b6576113b6612872565b6000918252602090912001546001600160a01b031692915050565b6000610a26600a611d0b565b6000808080808080806113f160078a611b2f565b61141157604051637d9160bf60e11b8152600481018a9052602401610622565b600061141e60078b611b3b565b905061142981611c91565b61ffff16985061143881611c9d565b61ffff16975061144781611cad565b61ffff16965061145681611cbd565b61ffff16955061146581611ccd565b62ffffff16945061147581611cde565b61ffff16935061148481611cee565b62ffffff16925060ff81901c915050919395975091939597565b6000546001600160a01b031633146114c957604051639f216c1360e01b815260040160405180910390fd5b306001600160a01b0316816001600160a01b03166388cc58e46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611511573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153591906128d0565b6001600160a01b03161461156757604051630a3e70af60e11b81526001600160a01b0382166004820152602401610622565b6004546001600160a01b039081169082168114156115a357604051630ded3b9560e31b81526001600160a01b0383166004820152602401610622565b600480546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f900d0e3d359f50e4f923ecdc06b401e07dbb9f485e17b07bcfc91a13000b277e91015b60405180910390a15050565b6000546001600160a01b0316331461162e57604051639f216c1360e01b815260040160405180910390fd5b6001600160a01b038116611655576040516391f3851560e01b815260040160405180910390fd5b6001546001600160a01b03161561167f5760405163716b1fbf60e01b815260040160405180910390fd5b61168881611d3f565b50565b6000546001600160a01b031633146116b657604051639f216c1360e01b815260040160405180910390fd5b6116c1600a82611de3565b6116e957604051638e888ef360e01b81526001600160a01b0382166004820152602401610622565b6040516001600160a01b038216907f0b767739217755d8af5a2ba75b181a19fa1750f8bb701f09311cb19a90140cb390600090a250565b6000546001600160a01b0316331461174b57604051639f216c1360e01b815260040160405180910390fd5b61175a600761ffff8316611df8565b61177d57604051637d9160bf60e11b815261ffff82166004820152602401610622565b60405161ffff8216907fdd86b848bb56ff540caa68683fa467d0e7eb5f8b2d44e4ee435742eeeae9be1390600090a250565b6000546001600160a01b031633146117da57604051639f216c1360e01b815260040160405180910390fd5b61168881611e04565b6000546001600160a01b0316331461180e57604051639f216c1360e01b815260040160405180910390fd5b6003548181141561183557604051631baa31e960e21b815260048101839052602401610622565b67016345785d8a000082111561186f57604051635e8988c160e01b81526004810183905267016345785d8a00006024820152604401610622565b600382905560408051828152602081018490527f5c34e91c94c78b662a45d0bd4a25a4e32c584c54a45a76e4a4d43be27ba40e5091016115f7565b6001546001600160a01b0316331415806118c2575033155b156118e057604051633982680960e11b815260040160405180910390fd5b61118533611d89565b600061059a82611ec3565b60008080806119038686611ece565b9097909650945050505050565b600060ff82901c61059a565b60006119288383611ef9565b9392505050565b60408051608081018252600080825260208201819052918101829052606081019190915261195d8484611bad565b6001600160a01b03918216600090815260066020908152604080832093851683529281528282209582529485528190208151608081018352905461ffff811682526201000081049093169481019490945260ff600160b01b83048116151591850191909152600160b81b90910416151560608301525092915050565b6001600160a01b03811660009081526001830160205260408120541515611928565b60008561ffff168761ffff161180611a185750610fff8661ffff16115b80611a2857506127108561ffff16115b80611a3857506109c48361ffff16115b80611a4a5750620fffff8262ffffff16115b15611a6857604051631c07203f60e01b815260040160405180910390fd5b5060109590951b630fff00001661ffff9690961695909517601c9390931b64fff0000000169290921760289190911b663fff0000000000161760369190911b693fffffc00000000000001617604e9290921b6b0fffc00000000000000000001691909117605c9190911b6dfffff0000000000000000000000016176dffffffffffffffffffffffffffff19919091161790565b60006113648484611b0d576000611b10565b60015b600180861b19929092169116841b1790565b6000611364848484611f23565b60006119288383611f40565b60006119288383611f4c565b6000611928836001600160a01b038416611fbc565b606060006119288361200b565b600061271071ffff00000000000000000000000000000000608084901b1604600160801b0162ffffff8416627fffff1901611ba48282612016565b95945050505050565b600080826001600160a01b0316846001600160a01b03161115611bce579192915b509192909150565b600060408303516020840351845180602087010180516002830161ffca811115611c085763c8c781396000526004601cfd5b6c5af43d3d93803e603357fd5bf3895289600d8a03527d6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d738160481b176035820160d81b1760218a03528060f01b835287603f8201601f8b036000f596505085611c775763301164256000526004601cfd5b90528552601f19850152603f199093019290925250919050565b600061ffff821661059a565b600061059a8260101c610fff1690565b600061059a82601c1c610fff1690565b600061059a8260281c613fff1690565b600061059a8260361c62ffffff1690565b600061059a82604e1c613fff1690565b600061059a82605c1c620fffff1690565b60006119288383611fbc565b600061059a825490565b8061ffff81168114611d3a576040516364ae406d60e01b815260040160405180910390fd5b919050565b600180546001600160a01b0319166001600160a01b0383169081179091556040517f68f49b346b94582a8b5f9d10e3fe3365318fe8f191ff8dce7c59c6cad06b02f590600090a250565b600080546001600160a01b038381166001600160a01b031980841682178555600180549091169055604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000611928836001600160a01b038416612278565b6000611928838361236b565b6001600160a01b038116611e2b57604051632573cfb960e21b815260040160405180910390fd5b6002546001600160a01b03908116908216811415611e6b57600254604051634fcea97160e01b81526001600160a01b039091166004820152602401610622565b600280546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f15d80a013f22151bc7246e3bc132e12828cde19de98870475e3fa7084015272191016115f7565b600061059a82611d0b565b60008080611edc858561191c565b600081815260029690960160205260409095205494959350505050565b6000826000018281548110611f1057611f10612872565b9060005260206000200154905092915050565b600082815260028401602052604081208290556113648484611cff565b60006119288383612388565b600081815260028301602052604081205480151580611f705750611f708484611f40565b6119285760405162461bcd60e51b815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610622565b60008181526001830160205260408120546120035750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561059a565b50600061059a565b606061059a826123a0565b600080808361202e5750600160801b915061059a9050565b50826000811215612040579015906000035b6210000081101561223957600160801b9250846fffffffffffffffffffffffffffffffff81111561207357911591600019045b60018216156120845792830260801c925b800260801c600282161561209a5792830260801c925b800260801c60048216156120b05792830260801c925b800260801c60088216156120c65792830260801c925b800260801c60108216156120dc5792830260801c925b800260801c60208216156120f25792830260801c925b800260801c60408216156121085792830260801c925b8002608090811c9082161561211f5792830260801c925b800260801c6101008216156121365792830260801c925b800260801c61020082161561214d5792830260801c925b800260801c6104008216156121645792830260801c925b800260801c61080082161561217b5792830260801c925b800260801c6110008216156121925792830260801c925b800260801c6120008216156121a95792830260801c925b800260801c6140008216156121c05792830260801c925b800260801c6180008216156121d75792830260801c925b800260801c620100008216156121ef5792830260801c925b800260801c620200008216156122075792830260801c925b800260801c6204000082161561221f5792830260801c925b800260801c620800008216156122375792830260801c925b505b8261226157604051631dba598d60e11b81526004810186905260248101859052604401610622565b8161226c5782611ba4565b611ba4836000196128ed565b6000818152600183016020526040812054801561236157600061229c6001836128b9565b85549091506000906122b0906001906128b9565b90508181146123155760008660000182815481106122d0576122d0612872565b90600052602060002001549050808760000184815481106122f3576122f3612872565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806123265761232661290f565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061059a565b600091505061059a565b6000818152600283016020526040812081905561192883836123ad565b60008181526001830160205260408120541515611928565b60606000611928836123b9565b60006119288383612278565b60608160000180548060200260200160405190810160405280929190818152602001828054801561240957602002820191906000526020600020905b8154815260200190600101908083116123f5575b50505050509050919050565b6020808252825182820181905260009190848201906040850190845b8181101561244d57835183529284019291840191600101612431565b50909695505050505050565b60006020828403121561246b57600080fd5b5035919050565b6001600160a01b038116811461168857600080fd5b803561ffff81168114611d3a57600080fd5b803562ffffff81168114611d3a57600080fd5b6000806000806000806000806000806101408b8d0312156124cc57600080fd5b8a356124d781612472565b995060208b01356124e781612472565b98506124f560408c01612487565b975061250360608c01612487565b965061251160808c01612487565b955061251f60a08c01612487565b945061252d60c08c01612487565b935061253b60e08c01612499565b925061254a6101008c01612487565b91506125596101208c01612499565b90509295989b9194979a5092959850565b60006020828403121561257c57600080fd5b813561192881612472565b80358015158114611d3a57600080fd5b60008060008060008060008060006101208a8c0312156125b657600080fd5b6125bf8a612487565b98506125cd60208b01612487565b97506125db60408b01612487565b96506125e960608b01612487565b95506125f760808b01612487565b945061260560a08b01612499565b935061261360c08b01612487565b925061262160e08b01612499565b91506126306101008b01612587565b90509295985092959850929598565b6000806040838503121561265257600080fd5b61265b83612487565b915061266960208401612587565b90509250929050565b6000806000806080858703121561268857600080fd5b843561269381612472565b935060208501356126a381612472565b92506126b160408601612499565b91506126bf60608601612487565b905092959194509250565b600080604083850312156126dd57600080fd5b82356126e881612472565b915060208301356126f881612472565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561244d5761276483855161ffff81511682526001600160a01b0360208201511660208301526040810151151560408301526060810151151560608301525050565b928401926080929092019160010161271f565b6000806000806080858703121561278d57600080fd5b843561279881612472565b935060208501356127a881612472565b92506127b660408601612487565b91506126bf60608601612587565b6000806000606084860312156127d957600080fd5b83356127e481612472565b925060208401356127f481612472565b929592945050506040919091013590565b815161ffff1681526020808301516001600160a01b0316908201526040808301511515908201526060808301511515908201526080810161059a565b60006020828403121561285357600080fd5b61192882612487565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156128b2576128b2612888565b5060010190565b6000828210156128cb576128cb612888565b500390565b6000602082840312156128e257600080fd5b815161192881612472565b60008261290a57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220fe4fd9c2069257bcac11964fb12f0b0aca377985f662148af0d45fd0b5cb549864736f6c634300080a0033000000000000000000000000c8fc59fceb8259534d8b10879273879eddf7eec00000000000000000000000000000000000000000000000000000048c27395000

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061020b5760003560e01c8063704037bd1161012a578063b0384781116100bd578063e30c39781161008c578063e92d0d5d11610071578063e92d0d5d14610490578063f9dca989146104a3578063fd90c2be146104ab57600080fd5b8063e30c39781461046c578063e74b981b1461047d57600080fd5b8063b038478114610420578063c42069ec14610433578063ddbfd94114610446578063e203a31f1461045957600080fd5b80638ce9aa1c116100f95780638ce9aa1c146103a05780638da5cb5b146103ae578063aabc4b3c146103bf578063af3710651461040f57600080fd5b8063704037bd1461035d578063715018a61461037d5780637daf5d661461038557806380c5061e1461039857600080fd5b80634e937c3a116101a25780636622e0d7116101715780636622e0d71461031b57806367ab8a4e1461033b57806369d56ea314610343578063701ab8c11461035657600080fd5b80634e937c3a146102db5780635a440923146102ed5780635b35875c14610300578063659ac74b1461030857600080fd5b8063379ee803116101de578063379ee803146102915780633c78a941146102a45780634ccb20c0146102b75780634cd161d3146102c857600080fd5b80630282c9c1146102105780630752092b1461022e578063093ff76914610259578063277218421461026e575b600080fd5b6102186104b3565b6040516102259190612415565b60405180910390f35b61024161023c366004612459565b61058d565b6040516001600160a01b039091168152602001610225565b61026c6102673660046124ac565b6105a0565b005b61028161027c36600461256a565b6106c9565b6040519015158152602001610225565b61026c61029f366004612597565b6106d6565b61026c6102b236600461256a565b610815565b6002546001600160a01b0316610241565b61026c6102d636600461263f565b610896565b6005545b604051908152602001610225565b61026c6102fb36600461256a565b610985565b610218610a1a565b610241610316366004612672565b610a2b565b61032e6103293660046126ca565b610f8f565b6040516102259190612703565b61026c611127565b61026c610351366004612777565b611187565b60016102df565b61037061036b3660046127c4565b611335565b6040516102259190612805565b61026c61136c565b610241610393366004612459565b6113a1565b6102df6113d1565b67016345785d8a00006102df565b6000546001600160a01b0316610241565b6103d26103cd366004612459565b6113dd565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c0830152151560e082015261010001610225565b6004546001600160a01b0316610241565b61026c61042e36600461256a565b61149e565b61026c61044136600461256a565b611603565b61026c61045436600461256a565b61168b565b61026c610467366004612841565b611720565b6001546001600160a01b0316610241565b61026c61048b36600461256a565b6117af565b61026c61049e366004612459565b6117e3565b61026c6118aa565b6003546102df565b606060006104c160076118e9565b90508015610589578067ffffffffffffffff8111156104e2576104e261285c565b60405190808252806020026020018201604052801561050b578160200160208202803683370190505b5091506000805b8281101561057a576000806105286007846118f4565b909250905061053681611910565b15610567578186858151811061054e5761054e612872565b6020908102919091010152836105638161289e565b9450505b5050806105739061289e565b9050610512565b5081811015610587578083525b505b5090565b600061059a600a8361191c565b92915050565b6000546001600160a01b031633146105cb57604051639f216c1360e01b815260040160405180910390fd5b60006105dc8b8b8b61ffff1661192f565b6020015190506001600160a01b03811661062b5760405163b65ee95360e01b81526001600160a01b03808d1660048301528b16602482015261ffff8a1660448201526064015b60405180910390fd5b604051633329c28d60e11b815261ffff808a16600483015280891660248301528088166044830152808716606483015262ffffff808716608484015290851660a4830152831660c48201526001600160a01b03821690636653851a9060e401600060405180830381600087803b1580156106a457600080fd5b505af11580156106b8573d6000803e3d6000fd5b505050505050505050505050505050565b600061059a600a836119d9565b6000546001600160a01b0316331461070157604051639f216c1360e01b815260040160405180910390fd5b60018961ffff16101561072d57604051634f958e7160e01b815261ffff8a166004820152602401610622565b600061073f818a8a8a8a8a8a8a6119fb565b905081156107575761075481600160ff611afb565b90505b610767600761ffff8c1683611b22565b506040805161ffff8b811682528a8116602083015289811682840152888116606083015262ffffff888116608084015287821660a0840152861660c08301529151918c16917f839844a256a87f87c9c835117d9a1c40be013954064c937072acb32d36db6a289181900360e00190a26040518215159061ffff8c16907f58a8b6a02b964cca2712e5a71d7b0d564a56b4a0f573b4c47f389341ade14cfd90600090a350505050505050505050565b6000546001600160a01b0316331461084057604051639f216c1360e01b815260040160405180910390fd5b806001600160a01b031663d3b9fbe46040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561087b57600080fd5b505af115801561088f573d6000803e3d6000fd5b5050505050565b6000546001600160a01b031633146108c157604051639f216c1360e01b815260040160405180910390fd5b6108d0600761ffff8416611b2f565b6108f357604051637d9160bf60e11b815261ffff83166004820152602401610622565b6000610904600761ffff8516611b3b565b905081151560ff82901c1515141561092f576040516311be38db60e11b815260040160405180910390fd5b61094c61ffff8416610943838560ff611afb565b60079190611b22565b506040518215159061ffff8516907f58a8b6a02b964cca2712e5a71d7b0d564a56b4a0f573b4c47f389341ade14cfd90600090a3505050565b6000546001600160a01b031633146109b057604051639f216c1360e01b815260040160405180910390fd5b6109bb600a82611b47565b6109e3576040516303ce0ad960e01b81526001600160a01b0382166004820152602401610622565b6040516001600160a01b038216907f84cc2115995684dcb0cd3d3a9565e3d32f075de81db70c8dc3a719b2a47af67e90600090a250565b6060610a266007611b5c565b905090565b6000610a3c600761ffff8416611b2f565b610a5f57604051637d9160bf60e11b815261ffff83166004820152602401610622565b6000610a70600761ffff8516611b3b565b90506000610a866000546001600160a01b031690565b6001600160a01b0316336001600160a01b0316149050610aa582611910565b158015610ab0575080155b15610ada576040516304fc2fe760e11b815233600482015261ffff85166024820152604401610622565b610ae5600a876119d9565b610b0d57604051638e888ef360e01b81526001600160a01b0387166004820152602401610622565b856001600160a01b0316876001600160a01b03161415610b4b57604051632f9b185360e01b81526001600160a01b0388166004820152602401610622565b610b558585611b69565b50600080610b638989611bad565b90925090506001600160a01b038216610b8f57604051632573cfb960e21b815260040160405180910390fd5b6001600160a01b0382811660009081526006602090815260408083208585168452825280832061ffff8b1684529091529020546201000090041615610c045760405163cb27a43560e01b81526001600160a01b03808b1660048301528916602482015261ffff87166044820152606401610622565b6004546001600160a01b031680610c2e576040516328b4fcf960e21b815260040160405180910390fd5b6040516bffffffffffffffffffffffff1960608c811b821660208401528b901b1660348201527fffff00000000000000000000000000000000000000000000000000000000000060f089901b166048820152610cdb908290604a0160408051601f198184030181528282526001600160a01b03808916602085015287169183019190915261ffff8b1660608301529060800160405160208183030381529060405280519060200120611bd6565b955050846001600160a01b03166347973bff610cf686611c91565b610cff87611c9d565b610d0888611cad565b610d1189611cbd565b610d1a8a611ccd565b610d238b611cde565b610d2c8c611cee565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e08a901b16815261ffff978816600482015295871660248701529386166044860152918516606485015262ffffff9081166084850152931660a4830152821660c4820152908a1660e482015261010401600060405180830381600087803b158015610dbb57600080fd5b505af1158015610dcf573d6000803e3d6000fd5b50506040805160808101825261ffff808b168083526001600160a01b03808c1660208086018281528c15158789019081526000606089018181528e8716808352600686528b83208f89168085529087528c84208a855287528c84209b518c549651955193511515600160b81b0260ff60b81b19941515600160b01b02949094167fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff96909a1662010000027fffffffffffffffffffff000000000000000000000000000000000000000000009097169b169a909a179490941792909216959095171790965560058054600181019091557f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b031916909217909155938152600c84528481209281529190925291909120610f1393509150611cff565b508561ffff16886001600160a01b03168a6001600160a01b03167f2c8d104b27c6b7f4492017a6f5cf3803043688934ebcaa6a03540beeaf976aff886001600580549050610f6191906128b9565b604080516001600160a01b03909316835260208301919091520160405180910390a450505050949350505050565b6060600080610f9e8585611bad565b6001600160a01b038083166000908152600c602090815260408083209385168352929052908120929450909250610fd482611d0b565b9050801561111d578067ffffffffffffffff811115610ff557610ff561285c565b60405190808252806020026020018201604052801561104757816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816110135790505b506001600160a01b03808616600090815260066020908152604080832093881683529290529081209196505b8281101561111a57600061108f61108a868461191c565b611d15565b6040805160808101825261ffff831680825260008181526020888152848220546001600160a01b03620100008204168286015260ff600160b01b8204811615159686019690965292909152879052600160b81b90049091161515606082015289519192509089908490811061110657611106612872565b602090810291909101015250600101611073565b50505b5050505092915050565b6000546001600160a01b0316331461115257604051639f216c1360e01b815260040160405180910390fd5b6001546001600160a01b031661117b5760405163ecfad6bf60e01b815260040160405180910390fd5b6111856000611d3f565b565b6000546001600160a01b031633146111b257604051639f216c1360e01b815260040160405180910390fd5b6000806111bf8686611bad565b6001600160a01b0380831660009081526006602090815260408083208486168452825280832061ffff808c1685529083529281902081516080810183529054938416815262010000840490941691840182905260ff600160b01b84048116151591850191909152600160b81b90920490911615156060830152929450909250906112795760405163102a919160e21b81526001600160a01b0380891660048301528716602482015261ffff86166044820152606401610622565b8315158160600151151514156112a157604051626ee66560e11b815260040160405180910390fd5b6001600160a01b0380841660009081526006602090815260408083208685168452825280832061ffff8a1684528252918290208054881515600160b81b0260ff60b81b1990911617905583015190519116907f44cf35361c9ff3c8c1397ec6410d5495cc481feaef35c9af11da1a637107de4f9061132490871515815260200190565b60405180910390a250505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915261136484848461192f565b949350505050565b6000546001600160a01b0316331461139757604051639f216c1360e01b815260040160405180910390fd5b6111856000611d89565b6000600582815481106113b6576113b6612872565b6000918252602090912001546001600160a01b031692915050565b6000610a26600a611d0b565b6000808080808080806113f160078a611b2f565b61141157604051637d9160bf60e11b8152600481018a9052602401610622565b600061141e60078b611b3b565b905061142981611c91565b61ffff16985061143881611c9d565b61ffff16975061144781611cad565b61ffff16965061145681611cbd565b61ffff16955061146581611ccd565b62ffffff16945061147581611cde565b61ffff16935061148481611cee565b62ffffff16925060ff81901c915050919395975091939597565b6000546001600160a01b031633146114c957604051639f216c1360e01b815260040160405180910390fd5b306001600160a01b0316816001600160a01b03166388cc58e46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611511573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153591906128d0565b6001600160a01b03161461156757604051630a3e70af60e11b81526001600160a01b0382166004820152602401610622565b6004546001600160a01b039081169082168114156115a357604051630ded3b9560e31b81526001600160a01b0383166004820152602401610622565b600480546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f900d0e3d359f50e4f923ecdc06b401e07dbb9f485e17b07bcfc91a13000b277e91015b60405180910390a15050565b6000546001600160a01b0316331461162e57604051639f216c1360e01b815260040160405180910390fd5b6001600160a01b038116611655576040516391f3851560e01b815260040160405180910390fd5b6001546001600160a01b03161561167f5760405163716b1fbf60e01b815260040160405180910390fd5b61168881611d3f565b50565b6000546001600160a01b031633146116b657604051639f216c1360e01b815260040160405180910390fd5b6116c1600a82611de3565b6116e957604051638e888ef360e01b81526001600160a01b0382166004820152602401610622565b6040516001600160a01b038216907f0b767739217755d8af5a2ba75b181a19fa1750f8bb701f09311cb19a90140cb390600090a250565b6000546001600160a01b0316331461174b57604051639f216c1360e01b815260040160405180910390fd5b61175a600761ffff8316611df8565b61177d57604051637d9160bf60e11b815261ffff82166004820152602401610622565b60405161ffff8216907fdd86b848bb56ff540caa68683fa467d0e7eb5f8b2d44e4ee435742eeeae9be1390600090a250565b6000546001600160a01b031633146117da57604051639f216c1360e01b815260040160405180910390fd5b61168881611e04565b6000546001600160a01b0316331461180e57604051639f216c1360e01b815260040160405180910390fd5b6003548181141561183557604051631baa31e960e21b815260048101839052602401610622565b67016345785d8a000082111561186f57604051635e8988c160e01b81526004810183905267016345785d8a00006024820152604401610622565b600382905560408051828152602081018490527f5c34e91c94c78b662a45d0bd4a25a4e32c584c54a45a76e4a4d43be27ba40e5091016115f7565b6001546001600160a01b0316331415806118c2575033155b156118e057604051633982680960e11b815260040160405180910390fd5b61118533611d89565b600061059a82611ec3565b60008080806119038686611ece565b9097909650945050505050565b600060ff82901c61059a565b60006119288383611ef9565b9392505050565b60408051608081018252600080825260208201819052918101829052606081019190915261195d8484611bad565b6001600160a01b03918216600090815260066020908152604080832093851683529281528282209582529485528190208151608081018352905461ffff811682526201000081049093169481019490945260ff600160b01b83048116151591850191909152600160b81b90910416151560608301525092915050565b6001600160a01b03811660009081526001830160205260408120541515611928565b60008561ffff168761ffff161180611a185750610fff8661ffff16115b80611a2857506127108561ffff16115b80611a3857506109c48361ffff16115b80611a4a5750620fffff8262ffffff16115b15611a6857604051631c07203f60e01b815260040160405180910390fd5b5060109590951b630fff00001661ffff9690961695909517601c9390931b64fff0000000169290921760289190911b663fff0000000000161760369190911b693fffffc00000000000001617604e9290921b6b0fffc00000000000000000001691909117605c9190911b6dfffff0000000000000000000000016176dffffffffffffffffffffffffffff19919091161790565b60006113648484611b0d576000611b10565b60015b600180861b19929092169116841b1790565b6000611364848484611f23565b60006119288383611f40565b60006119288383611f4c565b6000611928836001600160a01b038416611fbc565b606060006119288361200b565b600061271071ffff00000000000000000000000000000000608084901b1604600160801b0162ffffff8416627fffff1901611ba48282612016565b95945050505050565b600080826001600160a01b0316846001600160a01b03161115611bce579192915b509192909150565b600060408303516020840351845180602087010180516002830161ffca811115611c085763c8c781396000526004601cfd5b6c5af43d3d93803e603357fd5bf3895289600d8a03527d6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d738160481b176035820160d81b1760218a03528060f01b835287603f8201601f8b036000f596505085611c775763301164256000526004601cfd5b90528552601f19850152603f199093019290925250919050565b600061ffff821661059a565b600061059a8260101c610fff1690565b600061059a82601c1c610fff1690565b600061059a8260281c613fff1690565b600061059a8260361c62ffffff1690565b600061059a82604e1c613fff1690565b600061059a82605c1c620fffff1690565b60006119288383611fbc565b600061059a825490565b8061ffff81168114611d3a576040516364ae406d60e01b815260040160405180910390fd5b919050565b600180546001600160a01b0319166001600160a01b0383169081179091556040517f68f49b346b94582a8b5f9d10e3fe3365318fe8f191ff8dce7c59c6cad06b02f590600090a250565b600080546001600160a01b038381166001600160a01b031980841682178555600180549091169055604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000611928836001600160a01b038416612278565b6000611928838361236b565b6001600160a01b038116611e2b57604051632573cfb960e21b815260040160405180910390fd5b6002546001600160a01b03908116908216811415611e6b57600254604051634fcea97160e01b81526001600160a01b039091166004820152602401610622565b600280546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f15d80a013f22151bc7246e3bc132e12828cde19de98870475e3fa7084015272191016115f7565b600061059a82611d0b565b60008080611edc858561191c565b600081815260029690960160205260409095205494959350505050565b6000826000018281548110611f1057611f10612872565b9060005260206000200154905092915050565b600082815260028401602052604081208290556113648484611cff565b60006119288383612388565b600081815260028301602052604081205480151580611f705750611f708484611f40565b6119285760405162461bcd60e51b815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610622565b60008181526001830160205260408120546120035750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561059a565b50600061059a565b606061059a826123a0565b600080808361202e5750600160801b915061059a9050565b50826000811215612040579015906000035b6210000081101561223957600160801b9250846fffffffffffffffffffffffffffffffff81111561207357911591600019045b60018216156120845792830260801c925b800260801c600282161561209a5792830260801c925b800260801c60048216156120b05792830260801c925b800260801c60088216156120c65792830260801c925b800260801c60108216156120dc5792830260801c925b800260801c60208216156120f25792830260801c925b800260801c60408216156121085792830260801c925b8002608090811c9082161561211f5792830260801c925b800260801c6101008216156121365792830260801c925b800260801c61020082161561214d5792830260801c925b800260801c6104008216156121645792830260801c925b800260801c61080082161561217b5792830260801c925b800260801c6110008216156121925792830260801c925b800260801c6120008216156121a95792830260801c925b800260801c6140008216156121c05792830260801c925b800260801c6180008216156121d75792830260801c925b800260801c620100008216156121ef5792830260801c925b800260801c620200008216156122075792830260801c925b800260801c6204000082161561221f5792830260801c925b800260801c620800008216156122375792830260801c925b505b8261226157604051631dba598d60e11b81526004810186905260248101859052604401610622565b8161226c5782611ba4565b611ba4836000196128ed565b6000818152600183016020526040812054801561236157600061229c6001836128b9565b85549091506000906122b0906001906128b9565b90508181146123155760008660000182815481106122d0576122d0612872565b90600052602060002001549050808760000184815481106122f3576122f3612872565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806123265761232661290f565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061059a565b600091505061059a565b6000818152600283016020526040812081905561192883836123ad565b60008181526001830160205260408120541515611928565b60606000611928836123b9565b60006119288383612278565b60608160000180548060200260200160405190810160405280929190818152602001828054801561240957602002820191906000526020600020905b8154815260200190600101908083116123f5575b50505050509050919050565b6020808252825182820181905260009190848201906040850190845b8181101561244d57835183529284019291840191600101612431565b50909695505050505050565b60006020828403121561246b57600080fd5b5035919050565b6001600160a01b038116811461168857600080fd5b803561ffff81168114611d3a57600080fd5b803562ffffff81168114611d3a57600080fd5b6000806000806000806000806000806101408b8d0312156124cc57600080fd5b8a356124d781612472565b995060208b01356124e781612472565b98506124f560408c01612487565b975061250360608c01612487565b965061251160808c01612487565b955061251f60a08c01612487565b945061252d60c08c01612487565b935061253b60e08c01612499565b925061254a6101008c01612487565b91506125596101208c01612499565b90509295989b9194979a5092959850565b60006020828403121561257c57600080fd5b813561192881612472565b80358015158114611d3a57600080fd5b60008060008060008060008060006101208a8c0312156125b657600080fd5b6125bf8a612487565b98506125cd60208b01612487565b97506125db60408b01612487565b96506125e960608b01612487565b95506125f760808b01612487565b945061260560a08b01612499565b935061261360c08b01612487565b925061262160e08b01612499565b91506126306101008b01612587565b90509295985092959850929598565b6000806040838503121561265257600080fd5b61265b83612487565b915061266960208401612587565b90509250929050565b6000806000806080858703121561268857600080fd5b843561269381612472565b935060208501356126a381612472565b92506126b160408601612499565b91506126bf60608601612487565b905092959194509250565b600080604083850312156126dd57600080fd5b82356126e881612472565b915060208301356126f881612472565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561244d5761276483855161ffff81511682526001600160a01b0360208201511660208301526040810151151560408301526060810151151560608301525050565b928401926080929092019160010161271f565b6000806000806080858703121561278d57600080fd5b843561279881612472565b935060208501356127a881612472565b92506127b660408601612487565b91506126bf60608601612587565b6000806000606084860312156127d957600080fd5b83356127e481612472565b925060208401356127f481612472565b929592945050506040919091013590565b815161ffff1681526020808301516001600160a01b0316908201526040808301511515908201526060808301511515908201526080810161059a565b60006020828403121561285357600080fd5b61192882612487565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156128b2576128b2612888565b5060010190565b6000828210156128cb576128cb612888565b500390565b6000602082840312156128e257600080fd5b815161192881612472565b60008261290a57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220fe4fd9c2069257bcac11964fb12f0b0aca377985f662148af0d45fd0b5cb549864736f6c634300080a0033

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

000000000000000000000000c8fc59fceb8259534d8b10879273879eddf7eec00000000000000000000000000000000000000000000000000000048c27395000

-----Decoded View---------------
Arg [0] : feeRecipient (address): 0xC8FC59fCeb8259534d8B10879273879eddf7EEC0
Arg [1] : flashLoanFee (uint256): 5000000000000

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000c8fc59fceb8259534d8b10879273879eddf7eec0
Arg [1] : 0000000000000000000000000000000000000000000000000000048c27395000


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

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ 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.