AVAX Price: $49.89 (+0.39%)
 
Transaction Hash
Method
Block
From
To
Remove Liquidity543397522024-12-14 14:13:5228 hrs ago1734185632IN
Trader Joe: LBRouter
0 AVAX0.0217253725.25
Remove Liquidity543286892024-12-14 7:51:0234 hrs ago1734162662IN
Trader Joe: LBRouter
0 AVAX0.0202838525
Remove Liquidity543238612024-12-14 5:04:2237 hrs ago1734152662IN
Trader Joe: LBRouter
0 AVAX0.0215008826.5
Remove Liquidity543048402024-12-13 18:06:462 days ago1734113206IN
Trader Joe: LBRouter
0 AVAX0.0514222525
Remove Liquidity542196332024-12-11 17:21:354 days ago1733937695IN
Trader Joe: LBRouter
0 AVAX0.0228003626.5
Remove Liquidity...541778382024-12-10 17:35:445 days ago1733852144IN
Trader Joe: LBRouter
0 AVAX0.0251155328.50076824
Remove Liquidity541640912024-12-10 9:59:455 days ago1733824785IN
Trader Joe: LBRouter
0 AVAX0.0231903826.26
Remove Liquidity541292472024-12-09 14:28:066 days ago1733754486IN
Trader Joe: LBRouter
0 AVAX0.0555320327
Remove Liquidity541251032024-12-09 12:07:056 days ago1733746025IN
Trader Joe: LBRouter
0 AVAX0.0042353429.365
Remove Liquidity540762702024-12-08 7:45:307 days ago1733643930IN
Trader Joe: LBRouter
0 AVAX0.0224959226.5
Remove Liquidity...540598142024-12-07 22:13:117 days ago1733609591IN
Trader Joe: LBRouter
0 AVAX0.180731426.5
Remove Liquidity...540597502024-12-07 22:11:017 days ago1733609461IN
Trader Joe: LBRouter
0 AVAX0.348168626.5
Remove Liquidity...540461432024-12-07 14:32:138 days ago1733581933IN
Trader Joe: LBRouter
0 AVAX0.0224499226.5
Remove Liquidity...540411002024-12-07 11:38:328 days ago1733571512IN
Trader Joe: LBRouter
0 AVAX0.0230366326.5
Remove Liquidity...540119512024-12-06 18:53:338 days ago1733511213IN
Trader Joe: LBRouter
0 AVAX0.0221427126
Remove Liquidity539977892024-12-06 10:55:189 days ago1733482518IN
Trader Joe: LBRouter
0 AVAX0.0042227926
Set Approval For...539678132024-12-05 18:01:3110 days ago1733421691IN
Trader Joe: LBRouter
0 AVAX0.0005440725
Set Approval For...539677922024-12-05 18:00:4910 days ago1733421649IN
Trader Joe: LBRouter
0 AVAX0.0005440725
Remove Liquidity539215472024-12-04 16:05:2211 days ago1733328322IN
Trader Joe: LBRouter
0 AVAX0.0263496431.81086646
Remove Liquidity539081952024-12-04 8:40:2911 days ago1733301629IN
Trader Joe: LBRouter
0 AVAX0.0223552626.5
Remove Liquidity539053552024-12-04 7:04:0311 days ago1733295843IN
Trader Joe: LBRouter
0 AVAX0.0558642726.5
Remove Liquidity539025032024-12-04 5:28:3011 days ago1733290110IN
Trader Joe: LBRouter
0 AVAX0.0374704525.01
Remove Liquidity...539024882024-12-04 5:28:0011 days ago1733290080IN
Trader Joe: LBRouter
0 AVAX0.0865420725.01
Remove Liquidity538994452024-12-04 3:43:4111 days ago1733283821IN
Trader Joe: LBRouter
0 AVAX0.0552687726.5
Add Liquidity538525182024-12-03 1:31:0412 days ago1733189464IN
Trader Joe: LBRouter
0 AVAX0.0112155227.15
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
540119512024-12-06 18:53:338 days ago1733511213
Trader Joe: LBRouter
0.14116607 AVAX
540119512024-12-06 18:53:338 days ago1733511213
Trader Joe: LBRouter
0.14116607 AVAX
521168522024-10-22 20:40:5853 days ago1729629658
Trader Joe: LBRouter
1.16910804 AVAX
521168522024-10-22 20:40:5853 days ago1729629658
Trader Joe: LBRouter
1.16910804 AVAX
513137432024-10-03 13:44:4873 days ago1727963088
Trader Joe: LBRouter
8.23723228 AVAX
511880442024-09-30 13:41:0476 days ago1727703664
Trader Joe: LBRouter
17.734 AVAX
501363032024-09-05 3:48:08101 days ago1725508088
Trader Joe: LBRouter
58.88289852 AVAX
501363032024-09-05 3:48:08101 days ago1725508088
Trader Joe: LBRouter
58.88289852 AVAX
501077382024-09-04 11:08:53102 days ago1725448133
Trader Joe: LBRouter
0.0001 AVAX
495921782024-08-23 0:18:01114 days ago1724372281
Trader Joe: LBRouter
0.38782202 AVAX
495921782024-08-23 0:18:01114 days ago1724372281
Trader Joe: LBRouter
0.38782202 AVAX
488293362024-08-04 9:44:50133 days ago1722764690
Trader Joe: LBRouter
3.50327614 AVAX
488293362024-08-04 9:44:50133 days ago1722764690
Trader Joe: LBRouter
3.50327614 AVAX
483334702024-07-23 11:33:52145 days ago1721734432
Trader Joe: LBRouter
0.17201413 AVAX
483334702024-07-23 11:33:52145 days ago1721734432
Trader Joe: LBRouter
0.17201413 AVAX
479278342024-07-13 19:16:47154 days ago1720898207
Trader Joe: LBRouter
4.49781789 AVAX
479278342024-07-13 19:16:47154 days ago1720898207
Trader Joe: LBRouter
4.49781789 AVAX
479278122024-07-13 19:16:03154 days ago1720898163
Trader Joe: LBRouter
0.55613686 AVAX
479278122024-07-13 19:16:03154 days ago1720898163
Trader Joe: LBRouter
0.55613686 AVAX
475225422024-07-04 1:01:08164 days ago1720054868
Trader Joe: LBRouter
10.00042585 AVAX
475225422024-07-04 1:01:08164 days ago1720054868
Trader Joe: LBRouter
10.00042585 AVAX
472965332024-06-28 15:25:11170 days ago1719588311
Trader Joe: LBRouter
80.65972032 AVAX
472965332024-06-28 15:25:11170 days ago1719588311
Trader Joe: LBRouter
80.65972032 AVAX
468654732024-06-18 9:30:42180 days ago1718703042
Trader Joe: LBRouter
0.12772522 AVAX
468654732024-06-18 9:30:42180 days ago1718703042
Trader Joe: LBRouter
0.12772522 AVAX
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LBRouter

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 800 runs

Other Settings:
default evmVersion
File 1 of 25 : LBRouter.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

import "./LBErrors.sol";
import "./libraries/BinHelper.sol";
import "./libraries/Constants.sol";
import "./libraries/FeeHelper.sol";
import "./libraries/JoeLibrary.sol";
import "./libraries/Math512Bits.sol";
import "./libraries/SwapHelper.sol";
import "./libraries/TokenHelper.sol";
import "./interfaces/IJoePair.sol";
import "./interfaces/ILBToken.sol";
import "./interfaces/ILBRouter.sol";

/// @title Liquidity Book Router
/// @author Trader Joe
/// @notice Main contract to interact with to swap and manage liquidity on Joe V2 exchange.
contract LBRouter is ILBRouter {
    using TokenHelper for IERC20;
    using TokenHelper for IWAVAX;
    using FeeHelper for FeeHelper.FeeParameters;
    using Math512Bits for uint256;
    using SwapHelper for ILBPair.Bin;
    using JoeLibrary for uint256;

    ILBFactory public immutable override factory;
    IJoeFactory public immutable override oldFactory;
    IWAVAX public immutable override wavax;

    modifier onlyFactoryOwner() {
        if (msg.sender != factory.owner()) revert LBRouter__NotFactoryOwner();
        _;
    }

    modifier ensure(uint256 _deadline) {
        if (block.timestamp > _deadline) revert LBRouter__DeadlineExceeded(_deadline, block.timestamp);
        _;
    }

    modifier verifyInputs(uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath) {
        if (_pairBinSteps.length == 0 || _pairBinSteps.length + 1 != _tokenPath.length)
            revert LBRouter__LengthsMismatch();
        _;
    }

    /// @notice Constructor
    /// @param _factory LBFactory address
    /// @param _oldFactory Address of old factory (Joe V1)
    /// @param _wavax Address of WAVAX
    constructor(
        ILBFactory _factory,
        IJoeFactory _oldFactory,
        IWAVAX _wavax
    ) {
        factory = _factory;
        oldFactory = _oldFactory;
        wavax = _wavax;
    }

    /// @dev Receive function that only accept AVAX from the WAVAX contract
    receive() external payable {
        if (msg.sender != address(wavax)) revert LBRouter__SenderIsNotWAVAX();
    }

    /// @notice Returns the approximate id corresponding to the inputted price.
    /// Warning, the returned id may be inaccurate close to the start price of a bin
    /// @param _LBPair The address of the LBPair
    /// @param _price The price of y per x (multiplied by 1e36)
    /// @return The id corresponding to this price
    function getIdFromPrice(ILBPair _LBPair, uint256 _price) external view override returns (uint24) {
        return BinHelper.getIdFromPrice(_price, _LBPair.feeParameters().binStep);
    }

    /// @notice Returns the price corresponding to the inputted id
    /// @param _LBPair The address of the LBPair
    /// @param _id The id
    /// @return The price corresponding to this id
    function getPriceFromId(ILBPair _LBPair, uint24 _id) external view override returns (uint256) {
        return BinHelper.getPriceFromId(_id, _LBPair.feeParameters().binStep);
    }

    /// @notice Simulate a swap in
    /// @param _LBPair The address of the LBPair
    /// @param _amountOut The amount of token to receive
    /// @param _swapForY Whether you swap X for Y (true), or Y for X (false)
    /// @return amountIn The amount of token to send in order to receive _amountOut token
    /// @return feesIn The amount of fees paid in token sent
    function getSwapIn(
        ILBPair _LBPair,
        uint256 _amountOut,
        bool _swapForY
    ) public view override returns (uint256 amountIn, uint256 feesIn) {
        (uint256 _pairReserveX, uint256 _pairReserveY, uint256 _activeId) = _LBPair.getReservesAndId();

        if (_amountOut == 0 || (_swapForY ? _amountOut > _pairReserveY : _amountOut > _pairReserveX))
            revert LBRouter__WrongAmounts(_amountOut, _swapForY ? _pairReserveY : _pairReserveX); // If this is wrong, then we're sure the amounts sent are wrong

        FeeHelper.FeeParameters memory _fp = _LBPair.feeParameters();
        _fp.updateVariableFeeParameters(_activeId);

        uint256 _amountOutOfBin;
        uint256 _amountInWithFees;
        uint256 _reserve;
        // Performs the actual swap, bin per bin
        // It uses the findFirstNonEmptyBinId function to make sure the bin we're currently looking at
        // has liquidity in it.
        while (true) {
            {
                (uint256 _reserveX, uint256 _reserveY) = _LBPair.getBin(uint24(_activeId));
                _reserve = _swapForY ? _reserveY : _reserveX;
            }
            uint256 _price = BinHelper.getPriceFromId(_activeId, _fp.binStep);
            if (_reserve != 0) {
                _amountOutOfBin = _amountOut >= _reserve ? _reserve : _amountOut;
                uint256 _amountInToBin = _swapForY
                    ? _amountOutOfBin.shiftDivRoundUp(Constants.SCALE_OFFSET, _price)
                    : _price.mulShiftRoundUp(_amountOutOfBin, Constants.SCALE_OFFSET);

                // We update the fee, but we don't store the new volatility reference, volatility accumulated and indexRef to not penalize traders
                _fp.updateVolatilityAccumulated(_activeId);
                uint256 _fee = _fp.getFeeAmount(_amountInToBin);
                _amountInWithFees = _amountInToBin + _fee;

                if (_amountInWithFees + _reserve > type(uint112).max) revert LBRouter__SwapOverflows(_activeId);
                amountIn += _amountInWithFees;
                feesIn += _fee;
                _amountOut -= _amountOutOfBin;
            }

            if (_amountOut != 0) {
                _activeId = _LBPair.findFirstNonEmptyBinId(uint24(_activeId), _swapForY);
            } else {
                break;
            }
        }
        if (_amountOut != 0) revert LBRouter__BrokenSwapSafetyCheck(); // Safety check, but should never be false as it would have reverted on transfer
    }

    /// @notice Simulate a swap out
    /// @param _LBPair The address of the LBPair
    /// @param _amountIn The amount of token sent
    /// @param _swapForY Whether you swap X for Y (true), or Y for X (false)
    /// @return amountOut The amount of token received if _amountIn tokenX are sent
    /// @return feesIn The amount of fees paid in token sent
    function getSwapOut(
        ILBPair _LBPair,
        uint256 _amountIn,
        bool _swapForY
    ) external view override returns (uint256 amountOut, uint256 feesIn) {
        (, , uint256 _activeId) = _LBPair.getReservesAndId();

        FeeHelper.FeeParameters memory _fp = _LBPair.feeParameters();
        _fp.updateVariableFeeParameters(_activeId);
        ILBPair.Bin memory _bin;

        // Performs the actual swap, bin per bin
        // It uses the findFirstNonEmptyBinId function to make sure the bin we're currently looking at
        // has liquidity in it.
        while (true) {
            {
                (uint256 _reserveX, uint256 _reserveY) = _LBPair.getBin(uint24(_activeId));
                _bin = ILBPair.Bin(uint112(_reserveX), uint112(_reserveY), 0, 0);
            }
            if (_bin.reserveX != 0 || _bin.reserveY != 0) {
                (uint256 _amountInToBin, uint256 _amountOutOfBin, FeeHelper.FeesDistribution memory _fees) = _bin
                    .getAmounts(_fp, _activeId, _swapForY, _amountIn);

                if (_amountInToBin > type(uint112).max) revert LBRouter__BinReserveOverflows(_activeId);

                _amountIn -= _amountInToBin + _fees.total;
                feesIn += _fees.total;
                amountOut += _amountOutOfBin;
            }

            if (_amountIn != 0) {
                _activeId = _LBPair.findFirstNonEmptyBinId(uint24(_activeId), _swapForY);
            } else {
                break;
            }
        }
        if (_amountIn != 0) revert LBRouter__TooMuchTokensIn(_amountIn);
    }

    /// @notice Create a liquidity bin LBPair for _tokenX and _tokenY using the factory
    /// @param _tokenX The address of the first token
    /// @param _tokenY The address of the second token
    /// @param _activeId The active id of the pair
    /// @param _binStep The bin step in basis point, used to calculate log(1 + binStep)
    /// @return pair The address of the newly created LBPair
    function createLBPair(
        IERC20 _tokenX,
        IERC20 _tokenY,
        uint24 _activeId,
        uint16 _binStep
    ) external override returns (ILBPair pair) {
        pair = factory.createLBPair(_tokenX, _tokenY, _activeId, _binStep);
    }

    /// @notice Add liquidity while performing safety checks
    /// @dev This function is compliant with fee on transfer tokens
    /// @param _liquidityParameters The liquidity parameters
    /// @return depositIds Bin ids where the liquidity was actually deposited
    /// @return liquidityMinted Amounts of LBToken minted for each bin
    function addLiquidity(LiquidityParameters calldata _liquidityParameters)
        external
        override
        returns (uint256[] memory depositIds, uint256[] memory liquidityMinted)
    {
        ILBPair _LBPair = _getLBPairInformation(
            _liquidityParameters.tokenX,
            _liquidityParameters.tokenY,
            _liquidityParameters.binStep
        );
        if (_liquidityParameters.tokenX != _LBPair.tokenX()) revert LBRouter__WrongTokenOrder();

        _liquidityParameters.tokenX.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountX);
        _liquidityParameters.tokenY.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountY);

        (depositIds, liquidityMinted) = _addLiquidity(_liquidityParameters, _LBPair);
    }

    /// @notice Add liquidity with AVAX while performing safety checks
    /// @dev This function is compliant with fee on transfer tokens
    /// @param _liquidityParameters The liquidity parameters
    /// @return depositIds Bin ids where the liquidity was actually deposited
    /// @return liquidityMinted Amounts of LBToken minted for each bin
    function addLiquidityAVAX(LiquidityParameters calldata _liquidityParameters)
        external
        payable
        override
        returns (uint256[] memory depositIds, uint256[] memory liquidityMinted)
    {
        ILBPair _LBPair = _getLBPairInformation(
            _liquidityParameters.tokenX,
            _liquidityParameters.tokenY,
            _liquidityParameters.binStep
        );
        if (_liquidityParameters.tokenX != _LBPair.tokenX()) revert LBRouter__WrongTokenOrder();

        if (_liquidityParameters.tokenX == wavax && _liquidityParameters.amountX == msg.value) {
            _wavaxDepositAndTransfer(address(_LBPair), msg.value);
            _liquidityParameters.tokenY.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountY);
        } else if (_liquidityParameters.tokenY == wavax && _liquidityParameters.amountY == msg.value) {
            _liquidityParameters.tokenX.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountX);
            _wavaxDepositAndTransfer(address(_LBPair), msg.value);
        } else
            revert LBRouter__WrongAvaxLiquidityParameters(
                address(_liquidityParameters.tokenX),
                address(_liquidityParameters.tokenY),
                _liquidityParameters.amountX,
                _liquidityParameters.amountY,
                msg.value
            );

        (depositIds, liquidityMinted) = _addLiquidity(_liquidityParameters, _LBPair);
    }

    /// @notice Remove liquidity while performing safety checks
    /// @dev This function is compliant with fee on transfer tokens
    /// @param _tokenX The address of token X
    /// @param _tokenY The address of token Y
    /// @param _binStep The bin step of the LBPair
    /// @param _amountXMin The min amount to receive of token X
    /// @param _amountYMin The min amount to receive of token Y
    /// @param _ids The list of ids to burn
    /// @param _amounts The list of amounts to burn of each id in `_ids`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountX Amount of token X returned
    /// @return amountY Amount of token Y returned
    function removeLiquidity(
        IERC20 _tokenX,
        IERC20 _tokenY,
        uint16 _binStep,
        uint256 _amountXMin,
        uint256 _amountYMin,
        uint256[] memory _ids,
        uint256[] memory _amounts,
        address _to,
        uint256 _deadline
    ) external override ensure(_deadline) returns (uint256 amountX, uint256 amountY) {
        ILBPair _LBPair = _getLBPairInformation(_tokenX, _tokenY, _binStep);
        bool _isWrongOrder = _tokenX != _LBPair.tokenX();

        if (_isWrongOrder) (_amountXMin, _amountYMin) = (_amountYMin, _amountXMin);

        (amountX, amountY) = _removeLiquidity(_LBPair, _amountXMin, _amountYMin, _ids, _amounts, _to);

        if (_isWrongOrder) (amountX, amountY) = (amountY, amountX);
    }

    /// @notice Remove AVAX liquidity while performing safety checks
    /// @dev This function is **NOT** compliant with fee on transfer tokens.
    /// This is wanted as it would make users pays the fee on transfer twice,
    /// use the `removeLiquidity` function to remove liquidity with fee on transfer tokens.
    /// @param _token The address of token
    /// @param _binStep The bin step of the LBPair
    /// @param _amountTokenMin The min amount to receive of token
    /// @param _amountAVAXMin The min amount to receive of AVAX
    /// @param _ids The list of ids to burn
    /// @param _amounts The list of amounts to burn of each id in `_ids`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountToken Amount of token returned
    /// @return amountAVAX Amount of AVAX returned
    function removeLiquidityAVAX(
        IERC20 _token,
        uint16 _binStep,
        uint256 _amountTokenMin,
        uint256 _amountAVAXMin,
        uint256[] memory _ids,
        uint256[] memory _amounts,
        address payable _to,
        uint256 _deadline
    ) external override ensure(_deadline) returns (uint256 amountToken, uint256 amountAVAX) {
        ILBPair _LBPair = _getLBPairInformation(_token, IERC20(wavax), _binStep);

        bool _isAVAXTokenY = IERC20(wavax) == _LBPair.tokenY();
        {
            if (!_isAVAXTokenY) {
                (_amountTokenMin, _amountAVAXMin) = (_amountAVAXMin, _amountTokenMin);
            }

            (uint256 _amountX, uint256 _amountY) = _removeLiquidity(
                _LBPair,
                _amountTokenMin,
                _amountAVAXMin,
                _ids,
                _amounts,
                address(this)
            );

            (amountToken, amountAVAX) = _isAVAXTokenY ? (_amountX, _amountY) : (_amountY, _amountX);
        }

        _token.safeTransfer(_to, amountToken);

        wavax.withdraw(amountAVAX);
        _safeTransferAVAX(_to, amountAVAX);
    }

    /// @notice Swaps exact tokens for tokens while performing safety checks
    /// @param _amountIn The amount of token to send
    /// @param _amountOutMin The min amount of token to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountOut Output amount of the swap
    function swapExactTokensForTokens(
        uint256 _amountIn,
        uint256 _amountOutMin,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn);

        amountOut = _swapExactTokensForTokens(_amountIn, _pairs, _pairBinSteps, _tokenPath, _to);

        if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut);
    }

    /// @notice Swaps exact tokens for AVAX while performing safety checks
    /// @param _amountIn The amount of token to send
    /// @param _amountOutMinAVAX The min amount of AVAX to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountOut Output amount of the swap
    function swapExactTokensForAVAX(
        uint256 _amountIn,
        uint256 _amountOutMinAVAX,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address payable _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
            revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn);

        amountOut = _swapExactTokensForTokens(_amountIn, _pairs, _pairBinSteps, _tokenPath, address(this));

        if (_amountOutMinAVAX > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMinAVAX, amountOut);

        wavax.withdraw(amountOut);
        _safeTransferAVAX(_to, amountOut);
    }

    /// @notice Swaps exact AVAX for tokens while performing safety checks
    /// @param _amountOutMin The min amount of token to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountOut Output amount of the swap
    function swapExactAVAXForTokens(
        uint256 _amountOutMin,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    ) external payable override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        _wavaxDepositAndTransfer(_pairs[0], msg.value);

        amountOut = _swapExactTokensForTokens(msg.value, _pairs, _pairBinSteps, _tokenPath, _to);

        if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut);
    }

    /// @notice Swaps tokens for exact tokens while performing safety checks
    /// @param _amountOut The amount of token to receive
    /// @param _amountInMax The max amount of token to send
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountsIn Input amounts for every step of the swap
    function swapTokensForExactTokens(
        uint256 _amountOut,
        uint256 _amountInMax,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256[] memory amountsIn) {
        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
        amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountOut);

        if (amountsIn[0] > _amountInMax) revert LBRouter__MaxAmountInExceeded(_amountInMax, amountsIn[0]);

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], amountsIn[0]);

        uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, _to);

        if (_amountOutReal < _amountOut) revert LBRouter__InsufficientAmountOut(_amountOut, _amountOutReal);
    }

    /// @notice Swaps tokens for exact AVAX while performing safety checks
    /// @param _amountAVAXOut The amount of AVAX to receive
    /// @param _amountInMax The max amount of token to send
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountsIn Input amounts for every step of the swap
    function swapTokensForExactAVAX(
        uint256 _amountAVAXOut,
        uint256 _amountInMax,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address payable _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256[] memory amountsIn) {
        if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
            revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
        amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountAVAXOut);

        if (amountsIn[0] > _amountInMax) revert LBRouter__MaxAmountInExceeded(_amountInMax, amountsIn[0]);

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], amountsIn[0]);

        uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, address(this));

        if (_amountOutReal < _amountAVAXOut) revert LBRouter__InsufficientAmountOut(_amountAVAXOut, _amountOutReal);

        wavax.withdraw(_amountOutReal);
        _safeTransferAVAX(_to, _amountOutReal);
    }

    /// @notice Swaps AVAX for exact tokens while performing safety checks
    /// @dev Will refund any AVAX amount sent in excess to `msg.sender`
    /// @param _amountOut The amount of tokens to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountsIn Input amounts for every step of the swap
    function swapAVAXForExactTokens(
        uint256 _amountOut,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    )
        external
        payable
        override
        ensure(_deadline)
        verifyInputs(_pairBinSteps, _tokenPath)
        returns (uint256[] memory amountsIn)
    {
        if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
        amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountOut);

        if (amountsIn[0] > msg.value) revert LBRouter__MaxAmountInExceeded(msg.value, amountsIn[0]);

        _wavaxDepositAndTransfer(_pairs[0], amountsIn[0]);

        uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, _to);

        if (_amountOutReal < _amountOut) revert LBRouter__InsufficientAmountOut(_amountOut, _amountOutReal);

        if (msg.value > amountsIn[0]) _safeTransferAVAX(msg.sender, msg.value - amountsIn[0]);
    }

    /// @notice Swaps exact tokens for tokens while performing safety checks supporting for fee on transfer tokens
    /// @param _amountIn The amount of token to send
    /// @param _amountOutMin The min amount of token to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountOut Output amount of the swap
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 _amountIn,
        uint256 _amountOutMin,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        IERC20 _targetToken = _tokenPath[_pairs.length];

        uint256 _balanceBefore = _targetToken.balanceOf(_to);

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn);

        _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _tokenPath, _to);

        amountOut = _targetToken.balanceOf(_to) - _balanceBefore;
        if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut);
    }

    /// @notice Swaps exact tokens for AVAX while performing safety checks supporting for fee on transfer tokens
    /// @param _amountIn The amount of token to send
    /// @param _amountOutMinAVAX The min amount of AVAX to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountOut Output amount of the swap
    function swapExactTokensForAVAXSupportingFeeOnTransferTokens(
        uint256 _amountIn,
        uint256 _amountOutMinAVAX,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address payable _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
            revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        uint256 _balanceBefore = wavax.balanceOf(address(this));

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn);

        _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _tokenPath, address(this));

        amountOut = wavax.balanceOf(address(this)) - _balanceBefore;
        if (_amountOutMinAVAX > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMinAVAX, amountOut);

        wavax.withdraw(amountOut);
        _safeTransferAVAX(_to, amountOut);
    }

    /// @notice Swaps exact AVAX for tokens while performing safety checks supporting for fee on transfer tokens
    /// @param _amountOutMin The min amount of token to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountOut Output amount of the swap
    function swapExactAVAXForTokensSupportingFeeOnTransferTokens(
        uint256 _amountOutMin,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    ) external payable override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        IERC20 _targetToken = _tokenPath[_pairs.length];

        uint256 _balanceBefore = _targetToken.balanceOf(_to);

        _wavaxDepositAndTransfer(_pairs[0], msg.value);

        _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _tokenPath, _to);

        amountOut = _targetToken.balanceOf(_to) - _balanceBefore;
        if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut);
    }

    /// @notice Unstuck tokens that are sent to this contract by mistake
    /// @dev Only callable by the factory owner
    /// @param _token The address of the token
    /// @param _to The address of the user to send back the tokens
    /// @param _amount The amount to send
    function sweep(
        IERC20 _token,
        address _to,
        uint256 _amount
    ) external override onlyFactoryOwner {
        if (address(_token) == address(0)) {
            if (_amount == type(uint256).max) _amount = address(this).balance;
            _safeTransferAVAX(_to, _amount);
        } else {
            if (_amount == type(uint256).max) _amount = _token.balanceOf(address(this));
            _token.safeTransfer(_to, _amount);
        }
    }

    /// @notice Unstuck LBTokens that are sent to this contract by mistake
    /// @dev Only callable by the factory owner
    /// @param _lbToken The address of the LBToken
    /// @param _to The address of the user to send back the tokens
    /// @param _ids The list of token ids
    /// @param _amounts The list of amounts to send
    function sweepLBToken(
        ILBToken _lbToken,
        address _to,
        uint256[] calldata _ids,
        uint256[] calldata _amounts
    ) external override onlyFactoryOwner {
        _lbToken.safeBatchTransferFrom(address(this), _to, _ids, _amounts);
    }

    /// @notice Helper function to add liquidity
    /// @param _liq The liquidity parameter
    /// @param _LBPair LBPair where liquidity is deposited
    /// @return depositIds Bin ids where the liquidity was actually deposited
    /// @return liquidityMinted Amounts of LBToken minted for each bin
    function _addLiquidity(LiquidityParameters calldata _liq, ILBPair _LBPair)
        private
        ensure(_liq.deadline)
        returns (uint256[] memory depositIds, uint256[] memory liquidityMinted)
    {
        unchecked {
            if (_liq.deltaIds.length != _liq.distributionX.length && _liq.deltaIds.length != _liq.distributionY.length)
                revert LBRouter__LengthsMismatch();

            if (_liq.activeIdDesired > type(uint24).max || _liq.idSlippage > type(uint24).max)
                revert LBRouter__IdDesiredOverflows(_liq.activeIdDesired, _liq.idSlippage);

            (, , uint256 _activeId) = _LBPair.getReservesAndId();
            if (
                _liq.activeIdDesired + _liq.idSlippage < _activeId || _activeId + _liq.idSlippage < _liq.activeIdDesired
            ) revert LBRouter__IdSlippageCaught(_liq.activeIdDesired, _liq.idSlippage, _activeId);

            depositIds = new uint256[](_liq.deltaIds.length);
            for (uint256 i; i < depositIds.length; ++i) {
                int256 _id = int256(_activeId) + _liq.deltaIds[i];
                if (_id < 0 || uint256(_id) > type(uint24).max) revert LBRouter__IdOverflows(_id);
                depositIds[i] = uint256(_id);
            }

            uint256 _amountXAdded;
            uint256 _amountYAdded;

            (_amountXAdded, _amountYAdded, liquidityMinted) = _LBPair.mint(
                depositIds,
                _liq.distributionX,
                _liq.distributionY,
                _liq.to
            );

            if (_amountXAdded < _liq.amountXMin || _amountYAdded < _liq.amountYMin)
                revert LBRouter__AmountSlippageCaught(_liq.amountXMin, _amountXAdded, _liq.amountYMin, _amountYAdded);
        }
    }

    /// @notice Helper function to return the amounts in
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _pairs The list of pairs
    /// @param _tokenPath The swap path
    /// @param _amountOut The amount out
    /// @return amountsIn The list of amounts in
    function _getAmountsIn(
        uint256[] memory _pairBinSteps,
        address[] memory _pairs,
        IERC20[] memory _tokenPath,
        uint256 _amountOut
    ) private view returns (uint256[] memory amountsIn) {
        amountsIn = new uint256[](_tokenPath.length);
        // Avoid doing -1, as `_pairs.length == _pairBinSteps.length-1`
        amountsIn[_pairs.length] = _amountOut;

        for (uint256 i = _pairs.length; i != 0; i--) {
            IERC20 _token = _tokenPath[i - 1];
            uint256 _binStep = _pairBinSteps[i - 1];

            address _pair = _pairs[i - 1];

            if (_binStep == 0) {
                (uint256 _reserveIn, uint256 _reserveOut, ) = IJoePair(_pair).getReserves();
                if (_token > _tokenPath[i]) {
                    (_reserveIn, _reserveOut) = (_reserveOut, _reserveIn);
                }

                uint256 amountOut_ = amountsIn[i];
                amountsIn[i - 1] = amountOut_.getAmountIn(_reserveIn, _reserveOut);
            } else {
                (amountsIn[i - 1], ) = getSwapIn(ILBPair(_pair), amountsIn[i], ILBPair(_pair).tokenX() == _token);
            }
        }
    }

    /// @notice Helper function to remove liquidity
    /// @param _LBPair The address of the LBPair
    /// @param _amountXMin The min amount to receive of token X
    /// @param _amountYMin The min amount to receive of token Y
    /// @param _ids The list of ids to burn
    /// @param _amounts The list of amounts to burn of each id in `_ids`
    /// @param _to The address of the recipient
    /// @return amountX The amount of token X sent by the pair
    /// @return amountY The amount of token Y sent by the pair
    function _removeLiquidity(
        ILBPair _LBPair,
        uint256 _amountXMin,
        uint256 _amountYMin,
        uint256[] memory _ids,
        uint256[] memory _amounts,
        address _to
    ) private returns (uint256 amountX, uint256 amountY) {
        ILBToken(address(_LBPair)).safeBatchTransferFrom(msg.sender, address(_LBPair), _ids, _amounts);
        (amountX, amountY) = _LBPair.burn(_ids, _amounts, _to);
        if (amountX < _amountXMin || amountY < _amountYMin)
            revert LBRouter__AmountSlippageCaught(_amountXMin, amountX, _amountYMin, amountY);
    }

    /// @notice Helper function to swap exact tokens for tokens
    /// @param _amountIn The amount of token sent
    /// @param _pairs The list of pairs
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @return amountOut The amount of token sent to `_to`
    function _swapExactTokensForTokens(
        uint256 _amountIn,
        address[] memory _pairs,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to
    ) private returns (uint256 amountOut) {
        IERC20 _token;
        uint256 _binStep;
        address _recipient;
        address _pair;

        IERC20 _tokenNext = _tokenPath[0];
        amountOut = _amountIn;

        unchecked {
            for (uint256 i; i < _pairs.length; ++i) {
                _pair = _pairs[i];
                _binStep = _pairBinSteps[i];

                _token = _tokenNext;
                _tokenNext = _tokenPath[i + 1];

                _recipient = i + 1 == _pairs.length ? _to : _pairs[i + 1];

                if (_binStep == 0) {
                    (uint256 _reserve0, uint256 _reserve1, ) = IJoePair(_pair).getReserves();

                    if (_token < _tokenNext) {
                        amountOut = amountOut.getAmountOut(_reserve0, _reserve1);
                        IJoePair(_pair).swap(0, amountOut, _recipient, "");
                    } else {
                        amountOut = amountOut.getAmountOut(_reserve1, _reserve0);
                        IJoePair(_pair).swap(amountOut, 0, _recipient, "");
                    }
                } else {
                    bool _swapForY = _tokenNext == ILBPair(_pair).tokenY();

                    (uint256 _amountXOut, uint256 _amountYOut) = ILBPair(_pair).swap(_swapForY, _recipient);

                    if (_swapForY) amountOut = _amountYOut;
                    else amountOut = _amountXOut;
                }
            }
        }
    }

    /// @notice Helper function to swap tokens for exact tokens
    /// @param _pairs The array of pairs
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _amountsIn The list of amounts in
    /// @param _to The address of the recipient
    /// @return amountOut The amount of token sent to `_to`
    function _swapTokensForExactTokens(
        address[] memory _pairs,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        uint256[] memory _amountsIn,
        address _to
    ) private returns (uint256 amountOut) {
        IERC20 _token;
        uint256 _binStep;
        address _recipient;
        address _pair;

        IERC20 _tokenNext = _tokenPath[0];

        unchecked {
            for (uint256 i; i < _pairs.length; ++i) {
                _pair = _pairs[i];
                _binStep = _pairBinSteps[i];

                _token = _tokenNext;
                _tokenNext = _tokenPath[i + 1];

                _recipient = i + 1 == _pairs.length ? _to : _pairs[i + 1];

                if (_binStep == 0) {
                    amountOut = _amountsIn[i + 1];
                    if (_token < _tokenNext) {
                        IJoePair(_pair).swap(0, amountOut, _recipient, "");
                    } else {
                        IJoePair(_pair).swap(amountOut, 0, _recipient, "");
                    }
                } else {
                    bool _swapForY = _tokenNext == ILBPair(_pair).tokenY();

                    (uint256 _amountXOut, uint256 _amountYOut) = ILBPair(_pair).swap(_swapForY, _recipient);

                    if (_swapForY) amountOut = _amountYOut;
                    else amountOut = _amountXOut;
                }
            }
        }
    }

    /// @notice Helper function to swap exact tokens supporting for fee on transfer tokens
    /// @param _pairs The list of pairs
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    function _swapSupportingFeeOnTransferTokens(
        address[] memory _pairs,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to
    ) private {
        IERC20 _token;
        uint256 _binStep;
        address _recipient;
        address _pair;

        IERC20 _tokenNext = _tokenPath[0];

        unchecked {
            for (uint256 i; i < _pairs.length; ++i) {
                _pair = _pairs[i];
                _binStep = _pairBinSteps[i];

                _token = _tokenNext;
                _tokenNext = _tokenPath[i + 1];

                _recipient = i + 1 == _pairs.length ? _to : _pairs[i + 1];

                if (_binStep == 0) {
                    (uint256 _reserve0, uint256 _reserve1, ) = IJoePair(_pair).getReserves();
                    if (_token < _tokenNext) {
                        uint256 _amountIn = _token.balanceOf(_pair) - _reserve0;
                        uint256 _amountOut = _amountIn.getAmountOut(_reserve0, _reserve1);

                        IJoePair(_pair).swap(0, _amountOut, _recipient, "");
                    } else {
                        uint256 _amountIn = _token.balanceOf(_pair) - _reserve1;
                        uint256 _amountOut = _amountIn.getAmountOut(_reserve1, _reserve0);

                        IJoePair(_pair).swap(_amountOut, 0, _recipient, "");
                    }
                } else {
                    ILBPair(_pair).swap(_tokenNext == ILBPair(_pair).tokenY(), _recipient);
                }
            }
        }
    }

    /// @notice Helper function to return the address of the LBPair
    /// @dev Revert if the pair is not created yet
    /// @param _tokenX The address of the tokenX
    /// @param _tokenY The address of the tokenY
    /// @param _binStep The bin step of the LBPair
    /// @return The address of the LBPair
    function _getLBPairInformation(
        IERC20 _tokenX,
        IERC20 _tokenY,
        uint256 _binStep
    ) private view returns (ILBPair) {
        ILBPair _LBPair = factory.getLBPairInformation(_tokenX, _tokenY, _binStep).LBPair;
        if (address(_LBPair) == address(0))
            revert LBRouter__PairNotCreated(address(_tokenX), address(_tokenY), _binStep);
        return _LBPair;
    }

    /// @notice Helper function to return the address of the pair (v1 or v2, according to `_binStep`)
    /// @dev Revert if the pair is not created yet
    /// @param _binStep The bin step of the LBPair, 0 means using V1 pair, any other value will use V2
    /// @param _tokenX The address of the tokenX
    /// @param _tokenY The address of the tokenY
    /// @return _pair The address of the pair of binStep `_binStep`
    function _getPair(
        uint256 _binStep,
        IERC20 _tokenX,
        IERC20 _tokenY
    ) private view returns (address _pair) {
        if (_binStep == 0) {
            _pair = oldFactory.getPair(address(_tokenX), address(_tokenY));
            if (_pair == address(0)) revert LBRouter__PairNotCreated(address(_tokenX), address(_tokenY), _binStep);
        } else _pair = address(_getLBPairInformation(_tokenX, _tokenY, _binStep));
    }

    function _getPairs(uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath)
        private
        view
        returns (address[] memory pairs)
    {
        pairs = new address[](_pairBinSteps.length);

        IERC20 _token;
        IERC20 _tokenNext = _tokenPath[0];
        unchecked {
            for (uint256 i; i < pairs.length; ++i) {
                _token = _tokenNext;
                _tokenNext = _tokenPath[i + 1];

                pairs[i] = _getPair(_pairBinSteps[i], _token, _tokenNext);
            }
        }
    }

    /// @notice Helper function to transfer AVAX
    /// @param _to The address of the recipient
    /// @param _amount The AVAX amount to send
    function _safeTransferAVAX(address _to, uint256 _amount) private {
        (bool success, ) = _to.call{value: _amount}("");
        if (!success) revert LBRouter__FailedToSendAVAX(_to, _amount);
    }

    /// @notice Helper function to deposit and transfer wavax
    /// @param _to The address of the recipient
    /// @param _amount The AVAX amount to wrap
    function _wavaxDepositAndTransfer(address _to, uint256 _amount) private {
        wavax.deposit{value: _amount}();
        wavax.safeTransfer(_to, _amount);
    }
}

File 2 of 25 : 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 25 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 4 of 25 : LBErrors.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./interfaces/ILBPair.sol";

/** LBRouter errors */

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

/** LBToken errors */

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

/** LBFactory errors */

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

/** LBPair errors */

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

/** BinHelper errors */

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

/** Math128x128 errors */

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

/** Math512Bits errors */

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

/** Oracle errors */

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

/** PendingOwnable errors */

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

/** ReentrancyGuardUpgradeable errors */

error ReentrancyGuardUpgradeable__ReentrantCall();
error ReentrancyGuardUpgradeable__AlreadyInitialized();

/** SafeCast errors */

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

/** TreeMath errors */

error TreeMath__ErrorDepthSearch();

/** JoeLibrary errors */

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

/** TokenHelper errors */

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

/** LBQuoter errors */

error LBQuoter_InvalidLength();

File 5 of 25 : IJoeFactory.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.10;

/// @title Joe V1 Factory Interface
/// @notice Interface to interact with Joe V1 Factory
interface IJoeFactory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint256);

    function feeTo() external view returns (address);

    function feeToSetter() external view returns (address);

    function migrator() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);

    function allPairs(uint256) external view returns (address pair);

    function allPairsLength() external view returns (uint256);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;

    function setFeeToSetter(address) external;

    function setMigrator(address) external;
}

File 6 of 25 : IJoePair.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.10;

/// @title Joe V1 Pair Interface
/// @notice Interface to interact with Joe V1 Pairs
interface IJoePair {
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);

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

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

    function decimals() external pure returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function transfer(address to, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);

    function PERMIT_TYPEHASH() external pure returns (bytes32);

    function nonces(address owner) external view returns (uint256);

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint256);

    function factory() external view returns (address);

    function token0() external view returns (address);

    function token1() external view returns (address);

    function getReserves()
        external
        view
        returns (
            uint112 reserve0,
            uint112 reserve1,
            uint32 blockTimestampLast
        );

    function price0CumulativeLast() external view returns (uint256);

    function price1CumulativeLast() external view returns (uint256);

    function kLast() external view returns (uint256);

    function mint(address to) external returns (uint256 liquidity);

    function burn(address to) external returns (uint256 amount0, uint256 amount1);

    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to,
        bytes calldata data
    ) external;

    function skim(address to) external;

    function sync() external;

    function initialize(address, address) external;
}

File 7 of 25 : ILBFactory.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

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

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

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

    event FeeRecipientSet(address oldRecipient, address newRecipient);

    event FlashLoanFeeSet(uint256 oldFlashLoanFee, uint256 newFlashLoanFee);

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

    event FactoryLockedStatusUpdated(bool unlocked);

    event LBPairImplementationSet(address oldLBPairImplementation, address LBPairImplementation);

    event LBPairIgnoredStateChanged(ILBPair indexed LBPair, bool ignored);

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

    event PresetRemoved(uint256 indexed binStep);

    event QuoteAssetAdded(IERC20 indexed quoteAsset);

    event QuoteAssetRemoved(IERC20 indexed quoteAsset);

    function MAX_FEE() external pure returns (uint256);

    function MIN_BIN_STEP() external pure returns (uint256);

    function MAX_BIN_STEP() external pure returns (uint256);

    function MAX_PROTOCOL_SHARE() external pure returns (uint256);

    function LBPairImplementation() external view returns (address);

    function getNumberOfQuoteAssets() external view returns (uint256);

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

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

    function feeRecipient() external view returns (address);

    function flashLoanFee() external view returns (uint256);

    function creationUnlocked() external view returns (bool);

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

    function getNumberOfLBPairs() external view returns (uint256);

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

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

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

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

    function setLBPairImplementation(address LBPairImplementation) external;

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

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

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

    function removePreset(uint16 binStep) external;

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

    function setFeeRecipient(address feeRecipient) external;

    function setFlashLoanFee(uint256 flashLoanFee) external;

    function setFactoryLockedState(bool locked) external;

    function addQuoteAsset(IERC20 quoteAsset) external;

    function removeQuoteAsset(IERC20 quoteAsset) external;

    function forceDecay(ILBPair LBPair) external;
}

File 8 of 25 : ILBFlashLoanCallback.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

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

File 9 of 25 : ILBPair.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    event OracleSizeIncreased(uint256 previousSize, uint256 newSize);

    function tokenX() external view returns (IERC20);

    function tokenY() external view returns (IERC20);

    function factory() external view returns (ILBFactory);

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

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

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

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

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

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

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

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

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

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

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

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

    function increaseOracleLength(uint16 newSize) external;

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

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

    function setFeesParameters(bytes32 packedFeeParameters) external;

    function forceDecay() external;

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

File 10 of 25 : ILBRouter.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./IJoeFactory.sol";
import "./ILBPair.sol";
import "./ILBToken.sol";
import "./IWAVAX.sol";

/// @title Liquidity Book Router Interface
/// @author Trader Joe
/// @notice Required interface of LBRouter contract
interface ILBRouter {
    /// @dev The liquidity parameters, such as:
    /// - tokenX: The address of token X
    /// - tokenY: The address of token Y
    /// - binStep: The bin step of the pair
    /// - amountX: The amount to send of token X
    /// - amountY: The amount to send of token Y
    /// - amountXMin: The min amount of token X added to liquidity
    /// - amountYMin: The min amount of token Y added to liquidity
    /// - activeIdDesired: The active id that user wants to add liquidity from
    /// - idSlippage: The number of id that are allowed to slip
    /// - deltaIds: The list of delta ids to add liquidity (`deltaId = activeId - desiredId`)
    /// - distributionX: The distribution of tokenX with sum(distributionX) = 100e18 (100%) or 0 (0%)
    /// - distributionY: The distribution of tokenY with sum(distributionY) = 100e18 (100%) or 0 (0%)
    /// - to: The address of the recipient
    /// - deadline: The deadline of the tx
    struct LiquidityParameters {
        IERC20 tokenX;
        IERC20 tokenY;
        uint256 binStep;
        uint256 amountX;
        uint256 amountY;
        uint256 amountXMin;
        uint256 amountYMin;
        uint256 activeIdDesired;
        uint256 idSlippage;
        int256[] deltaIds;
        uint256[] distributionX;
        uint256[] distributionY;
        address to;
        uint256 deadline;
    }

    function factory() external view returns (ILBFactory);

    function oldFactory() external view returns (IJoeFactory);

    function wavax() external view returns (IWAVAX);

    function getIdFromPrice(ILBPair LBPair, uint256 price) external view returns (uint24);

    function getPriceFromId(ILBPair LBPair, uint24 id) external view returns (uint256);

    function getSwapIn(
        ILBPair LBPair,
        uint256 amountOut,
        bool swapForY
    ) external view returns (uint256 amountIn, uint256 feesIn);

    function getSwapOut(
        ILBPair LBPair,
        uint256 amountIn,
        bool swapForY
    ) external view returns (uint256 amountOut, uint256 feesIn);

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

    function addLiquidity(LiquidityParameters calldata liquidityParameters)
        external
        returns (uint256[] memory depositIds, uint256[] memory liquidityMinted);

    function addLiquidityAVAX(LiquidityParameters calldata liquidityParameters)
        external
        payable
        returns (uint256[] memory depositIds, uint256[] memory liquidityMinted);

    function removeLiquidity(
        IERC20 tokenX,
        IERC20 tokenY,
        uint16 binStep,
        uint256 amountXMin,
        uint256 amountYMin,
        uint256[] memory ids,
        uint256[] memory amounts,
        address to,
        uint256 deadline
    ) external returns (uint256 amountX, uint256 amountY);

    function removeLiquidityAVAX(
        IERC20 token,
        uint16 binStep,
        uint256 amountTokenMin,
        uint256 amountAVAXMin,
        uint256[] memory ids,
        uint256[] memory amounts,
        address payable to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountAVAX);

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external returns (uint256 amountOut);

    function swapExactTokensForAVAX(
        uint256 amountIn,
        uint256 amountOutMinAVAX,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address payable to,
        uint256 deadline
    ) external returns (uint256 amountOut);

    function swapExactAVAXForTokens(
        uint256 amountOutMin,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external payable returns (uint256 amountOut);

    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amountsIn);

    function swapTokensForExactAVAX(
        uint256 amountOut,
        uint256 amountInMax,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address payable to,
        uint256 deadline
    ) external returns (uint256[] memory amountsIn);

    function swapAVAXForExactTokens(
        uint256 amountOut,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amountsIn);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external returns (uint256 amountOut);

    function swapExactTokensForAVAXSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMinAVAX,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address payable to,
        uint256 deadline
    ) external returns (uint256 amountOut);

    function swapExactAVAXForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external payable returns (uint256 amountOut);

    function sweep(
        IERC20 token,
        address to,
        uint256 amount
    ) external;

    function sweepLBToken(
        ILBToken _lbToken,
        address _to,
        uint256[] calldata _ids,
        uint256[] calldata _amounts
    ) external;
}

File 11 of 25 : ILBToken.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/utils/introspection/IERC165.sol";

/// @title Liquidity Book Token Interface
/// @author Trader Joe
/// @notice Required interface of LBToken contract
interface ILBToken is IERC165 {
    event TransferSingle(address indexed sender, address indexed from, address indexed to, 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 balanceOf(address account, uint256 id) external view returns (uint256);

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

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

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

    function setApprovalForAll(address sender, bool approved) external;

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount
    ) external;

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata id,
        uint256[] calldata amount
    ) external;
}

File 12 of 25 : 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 {
    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 13 of 25 : IWAVAX.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

/// @title WAVAX Interface
/// @notice Required interface of Wrapped AVAX contract
interface IWAVAX is IERC20 {
    function deposit() external payable;

    function withdraw(uint256) external;
}

File 14 of 25 : BinHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

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

    int256 private constant REAL_ID_SHIFT = 1 << 23;

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

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

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

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

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

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

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

File 15 of 25 : 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 {
    /// @notice Returns the closest non-zero bit of `integer` to the right (of left) of the `bit` bits that is not `bit`
    /// @param _integer The integer as a uint256
    /// @param _bit The bit index
    /// @param _rightSide Whether we're searching in the right side of the tree (true) or the left side (false)
    /// @return The index of the closest non-zero bit. If there is no closest bit, it returns max(uint256)
    function closestBit(
        uint256 _integer,
        uint8 _bit,
        bool _rightSide
    ) internal pure returns (uint256) {
        return _rightSide ? closestBitRight(_integer, _bit - 1) : closestBitLeft(_integer, _bit + 1);
    }

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

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

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

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

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

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

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

            return 255 - lsb;
        }
    }
}

File 16 of 25 : Constants.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

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

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

File 17 of 25 : FeeDistributionHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";
import "./Constants.sol";
import "./FeeHelper.sol";

/// @title Liquidity Book Fee Distribution Helper Library
/// @author Trader Joe
/// @notice Helper contract used for fees distribution calculations
library FeeDistributionHelper {
    /// @notice Calculate the tokenPerShare when fees are added
    /// @param _fees The fees received by the pair
    /// @param _totalSupply the total supply of a specific bin
    function getTokenPerShare(FeeHelper.FeesDistribution memory _fees, uint256 _totalSupply)
        internal
        pure
        returns (uint256)
    {
        unchecked {
            // This can't overflow as `totalFees >= protocolFees`,
            // shift can't overflow as we shift fees that are a uint128, by 128 bits.
            // The result will always be smaller than max(uint256)
            return ((uint256(_fees.total) - _fees.protocol) << Constants.SCALE_OFFSET) / _totalSupply;
        }
    }
}

File 18 of 25 : FeeHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

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

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

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

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

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

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

        updateVolatilityAccumulated(_fp, _activeId);
    }

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

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

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

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

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

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

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

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

File 19 of 25 : JoeLibrary.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.10;

import "../LBErrors.sol";

/// @title Liquidity Book Joe Library Helper Library
/// @author Trader Joe
/// @notice Helper contract used for Joe V1 related calculations
library JoeLibrary {
    // returns sorted token addresses, used to handle return values from pairs sorted in this order
    function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
        if (tokenA == tokenB) revert JoeLibrary__IdenticalAddresses();
        (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        if (token0 == address(0)) revert JoeLibrary__AddressZero();
    }

    // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) internal pure returns (uint256 amountB) {
        if (amountA == 0) revert JoeLibrary__InsufficientAmount();
        if (reserveA == 0 || reserveB == 0) revert JoeLibrary__InsufficientLiquidity();
        amountB = (amountA * reserveB) / reserveA;
    }

    // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
    function getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut
    ) internal pure returns (uint256 amountOut) {
        if (amountIn == 0) revert JoeLibrary__InsufficientAmount();
        if (reserveIn == 0 || reserveOut == 0) revert JoeLibrary__InsufficientLiquidity();
        uint256 amountInWithFee = amountIn * 997;
        uint256 numerator = amountInWithFee * reserveOut;
        uint256 denominator = reserveIn * 1000 + amountInWithFee;
        amountOut = numerator / denominator;
    }

    // given an output amount of an asset and pair reserves, returns a required input amount of the other asset
    function getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut
    ) internal pure returns (uint256 amountIn) {
        if (amountOut == 0) revert JoeLibrary__InsufficientAmount();
        if (reserveIn == 0 || reserveOut == 0) revert JoeLibrary__InsufficientLiquidity();
        uint256 numerator = reserveIn * amountOut * 1000;
        uint256 denominator = (reserveOut - amountOut) * 997;
        amountIn = numerator / denominator + 1;
    }
}

File 20 of 25 : Math128x128.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

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

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

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

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

        x >>= 1;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 21 of 25 : Math512Bits.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 22 of 25 : SafeCast.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 23 of 25 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

File 24 of 25 : SwapHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./BinHelper.sol";
import "./Constants.sol";
import "./FeeDistributionHelper.sol";
import "./FeeHelper.sol";
import "./Math512Bits.sol";
import "./SafeMath.sol";
import "../interfaces/ILBPair.sol";

/// @title Liquidity Book Swap Helper Library
/// @author Trader Joe
/// @notice Helper contract used for calculating swaps, fees and reserves changes
library SwapHelper {
    using Math512Bits for uint256;
    using FeeHelper for FeeHelper.FeeParameters;
    using SafeMath for uint256;
    using FeeDistributionHelper for FeeHelper.FeesDistribution;

    /// @notice Returns the swap amounts in the current bin
    /// @param bin The bin information
    /// @param fp The fee parameters
    /// @param activeId The active id of the pair
    /// @param swapForY Whether you've swapping token X for token Y (true) or token Y for token X (false)
    /// @param amountIn The amount sent by the user
    /// @return amountInToBin The amount of token that is added to the bin without the fees
    /// @return amountOutOfBin The amount of token that is removed from the bin
    /// @return fees The swap fees
    function getAmounts(
        ILBPair.Bin memory bin,
        FeeHelper.FeeParameters memory fp,
        uint256 activeId,
        bool swapForY,
        uint256 amountIn
    )
        internal
        pure
        returns (
            uint256 amountInToBin,
            uint256 amountOutOfBin,
            FeeHelper.FeesDistribution memory fees
        )
    {
        uint256 _price = BinHelper.getPriceFromId(activeId, fp.binStep);

        uint256 _reserve;
        uint256 _maxAmountInToBin;
        if (swapForY) {
            _reserve = bin.reserveY;
            _maxAmountInToBin = _reserve.shiftDivRoundUp(Constants.SCALE_OFFSET, _price);
        } else {
            _reserve = bin.reserveX;
            _maxAmountInToBin = _price.mulShiftRoundUp(_reserve, Constants.SCALE_OFFSET);
        }

        fp.updateVolatilityAccumulated(activeId);
        fees = fp.getFeeAmountDistribution(fp.getFeeAmount(_maxAmountInToBin));

        if (_maxAmountInToBin + fees.total <= amountIn) {
            amountInToBin = _maxAmountInToBin;
            amountOutOfBin = _reserve;
        } else {
            fees = fp.getFeeAmountDistribution(fp.getFeeAmountFrom(amountIn));
            amountInToBin = amountIn - fees.total;
            amountOutOfBin = swapForY
                ? _price.mulShiftRoundDown(amountInToBin, Constants.SCALE_OFFSET)
                : amountInToBin.shiftDivRoundDown(Constants.SCALE_OFFSET, _price);
            // Safety check in case rounding returns a higher value than expected
            if (amountOutOfBin > _reserve) amountOutOfBin = _reserve;
        }
    }

    /// @notice Update the fees of the pair and accumulated token per share of the bin
    /// @param bin The bin information
    /// @param pairFees The current fees of the pair information
    /// @param fees The fees amounts added to the pairFees
    /// @param swapForY whether the token sent was Y (true) or X (false)
    /// @param totalSupply The total supply of the token id
    function updateFees(
        ILBPair.Bin memory bin,
        FeeHelper.FeesDistribution memory pairFees,
        FeeHelper.FeesDistribution memory fees,
        bool swapForY,
        uint256 totalSupply
    ) internal pure {
        pairFees.total += fees.total;
        // unsafe math is fine because total >= protocol
        unchecked {
            pairFees.protocol += fees.protocol;
        }

        if (swapForY) {
            bin.accTokenXPerShare += fees.getTokenPerShare(totalSupply);
        } else {
            bin.accTokenYPerShare += fees.getTokenPerShare(totalSupply);
        }
    }

    /// @notice Update reserves
    /// @param bin The bin information
    /// @param pair The pair information
    /// @param swapForY whether the token sent was Y (true) or X (false)
    /// @param amountInToBin The amount of token that is added to the bin without fees
    /// @param amountOutOfBin The amount of token that is removed from the bin
    function updateReserves(
        ILBPair.Bin memory bin,
        ILBPair.PairInformation memory pair,
        bool swapForY,
        uint112 amountInToBin,
        uint112 amountOutOfBin
    ) internal pure {
        if (swapForY) {
            bin.reserveX += amountInToBin;

            unchecked {
                bin.reserveY -= amountOutOfBin;
                pair.reserveX += uint136(amountInToBin);
                pair.reserveY -= uint136(amountOutOfBin);
            }
        } else {
            bin.reserveY += amountInToBin;

            unchecked {
                bin.reserveX -= amountOutOfBin;
                pair.reserveX -= uint136(amountOutOfBin);
                pair.reserveY += uint136(amountInToBin);
            }
        }
    }
}

File 25 of 25 : TokenHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

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

import "../LBErrors.sol";

/// @title Safe Transfer
/// @author Trader Joe
/// @notice Wrappers around ERC20 operations that throw on failure (when the token
/// contract returns false). Tokens that return no value (and instead revert or
/// throw on failure) are also supported, non-reverting calls are assumed to be
/// successful.
/// To use this library you can add a `using TokenHelper for IERC20;` statement to your contract,
/// which allows you to call the safe operation as `token.safeTransfer(...)`
library TokenHelper {
    /// @notice Transfers token only if the amount is greater than zero
    /// @param token The address of the token
    /// @param owner The owner of the tokens
    /// @param recipient The address of the recipient
    /// @param amount The amount to send
    function safeTransferFrom(
        IERC20 token,
        address owner,
        address recipient,
        uint256 amount
    ) internal {
        if (amount != 0) {
            bytes memory data = abi.encodeWithSelector(token.transferFrom.selector, owner, recipient, amount);

            bytes memory returnData = _callAndCatchError(address(token), data);

            if (returnData.length > 0 && !abi.decode(returnData, (bool))) revert TokenHelper__TransferFailed();
        }
    }

    /// @notice Transfers token only if the amount is greater than zero
    /// @param token The address of the token
    /// @param recipient The address of the recipient
    /// @param amount The amount to send
    function safeTransfer(
        IERC20 token,
        address recipient,
        uint256 amount
    ) internal {
        if (amount != 0) {
            bytes memory data = abi.encodeWithSelector(token.transfer.selector, recipient, amount);

            bytes memory returnData = _callAndCatchError(address(token), data);

            if (returnData.length > 0 && !abi.decode(returnData, (bool))) revert TokenHelper__TransferFailed();
        }
    }

    /// @notice Returns the amount of token received by the pair
    /// @param token The address of the token
    /// @param reserve The total reserve of token
    /// @param fees The total fees of token
    /// @return The amount received by the pair
    function received(
        IERC20 token,
        uint256 reserve,
        uint256 fees
    ) internal view returns (uint256) {
        uint256 _internalBalance;
        unchecked {
            _internalBalance = reserve + fees;
        }
        return token.balanceOf(address(this)) - _internalBalance;
    }

    /// @notice Private view function to perform a low level call on `target`
    /// @dev Revert if the call doesn't succeed
    /// @param target The address of the account
    /// @param data The data to execute on `target`
    /// @return returnData The data returned by the call
    function _callAndCatchError(address target, bytes memory data) private returns (bytes memory) {
        (bool success, bytes memory returnData) = target.call(data);

        if (success) {
            if (returnData.length == 0 && !_isContract(target)) revert TokenHelper__NonContract();
        } else {
            if (returnData.length == 0) revert TokenHelper__CallFailed();
            else {
                // Look for revert reason and bubble it up if present
                assembly {
                    revert(add(32, returnData), mload(returnData))
                }
            }
        }

        return returnData;
    }

    /// @notice Private view function to return if an address is a contract
    /// @dev It is unsafe to assume that an address for which this function returns
    /// false is an externally-owned account (EOA) and not a contract.
    ///
    /// Among others, `isContract` will return false for the following
    /// types of addresses:
    ///  - an externally-owned account
    ///  - a contract in construction
    ///  - an address where a contract will be created
    ///  - an address where a contract lived, but was destroyed
    /// @param account The address of the account
    /// @return Whether the account is a contract (true) or not (false)
    function _isContract(address account) private view returns (bool) {
        return account.code.length > 0;
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract ILBFactory","name":"_factory","type":"address"},{"internalType":"contract IJoeFactory","name":"_oldFactory","type":"address"},{"internalType":"contract IWAVAX","name":"_wavax","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"bp","type":"uint256"}],"name":"BinHelper__BinStepOverflows","type":"error"},{"inputs":[],"name":"BinHelper__IdOverflows","type":"error"},{"inputs":[],"name":"JoeLibrary__InsufficientAmount","type":"error"},{"inputs":[],"name":"JoeLibrary__InsufficientLiquidity","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountXMin","type":"uint256"},{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountYMin","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"name":"LBRouter__AmountSlippageCaught","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"LBRouter__BinReserveOverflows","type":"error"},{"inputs":[],"name":"LBRouter__BrokenSwapSafetyCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"currentTimestamp","type":"uint256"}],"name":"LBRouter__DeadlineExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LBRouter__FailedToSendAVAX","type":"error"},{"inputs":[{"internalType":"uint256","name":"idDesired","type":"uint256"},{"internalType":"uint256","name":"idSlippage","type":"uint256"}],"name":"LBRouter__IdDesiredOverflows","type":"error"},{"inputs":[{"internalType":"int256","name":"id","type":"int256"}],"name":"LBRouter__IdOverflows","type":"error"},{"inputs":[{"internalType":"uint256","name":"activeIdDesired","type":"uint256"},{"internalType":"uint256","name":"idSlippage","type":"uint256"},{"internalType":"uint256","name":"activeId","type":"uint256"}],"name":"LBRouter__IdSlippageCaught","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"LBRouter__InsufficientAmountOut","type":"error"},{"inputs":[{"internalType":"address","name":"wrongToken","type":"address"}],"name":"LBRouter__InvalidTokenPath","type":"error"},{"inputs":[],"name":"LBRouter__LengthsMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"LBRouter__MaxAmountInExceeded","type":"error"},{"inputs":[],"name":"LBRouter__NotFactoryOwner","type":"error"},{"inputs":[{"internalType":"address","name":"tokenX","type":"address"},{"internalType":"address","name":"tokenY","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBRouter__PairNotCreated","type":"error"},{"inputs":[],"name":"LBRouter__SenderIsNotWAVAX","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"LBRouter__SwapOverflows","type":"error"},{"inputs":[{"internalType":"uint256","name":"excess","type":"uint256"}],"name":"LBRouter__TooMuchTokensIn","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"reserve","type":"uint256"}],"name":"LBRouter__WrongAmounts","type":"error"},{"inputs":[{"internalType":"address","name":"tokenX","type":"address"},{"internalType":"address","name":"tokenY","type":"address"},{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"},{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"LBRouter__WrongAvaxLiquidityParameters","type":"error"},{"inputs":[],"name":"LBRouter__WrongTokenOrder","type":"error"},{"inputs":[],"name":"Math128x128__LogUnderflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"int256","name":"y","type":"int256"}],"name":"Math128x128__PowerUnderflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"Math512Bits__MulDivOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"offset","type":"uint256"}],"name":"Math512Bits__MulShiftOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"}],"name":"Math512Bits__OffsetOverflows","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"SafeCast__Exceeds128Bits","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"SafeCast__Exceeds40Bits","type":"error"},{"inputs":[],"name":"TokenHelper__CallFailed","type":"error"},{"inputs":[],"name":"TokenHelper__NonContract","type":"error"},{"inputs":[],"name":"TokenHelper__TransferFailed","type":"error"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"},{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"},{"internalType":"uint256","name":"amountXMin","type":"uint256"},{"internalType":"uint256","name":"amountYMin","type":"uint256"},{"internalType":"uint256","name":"activeIdDesired","type":"uint256"},{"internalType":"uint256","name":"idSlippage","type":"uint256"},{"internalType":"int256[]","name":"deltaIds","type":"int256[]"},{"internalType":"uint256[]","name":"distributionX","type":"uint256[]"},{"internalType":"uint256[]","name":"distributionY","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ILBRouter.LiquidityParameters","name":"_liquidityParameters","type":"tuple"}],"name":"addLiquidity","outputs":[{"internalType":"uint256[]","name":"depositIds","type":"uint256[]"},{"internalType":"uint256[]","name":"liquidityMinted","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"},{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"},{"internalType":"uint256","name":"amountXMin","type":"uint256"},{"internalType":"uint256","name":"amountYMin","type":"uint256"},{"internalType":"uint256","name":"activeIdDesired","type":"uint256"},{"internalType":"uint256","name":"idSlippage","type":"uint256"},{"internalType":"int256[]","name":"deltaIds","type":"int256[]"},{"internalType":"uint256[]","name":"distributionX","type":"uint256[]"},{"internalType":"uint256[]","name":"distributionY","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ILBRouter.LiquidityParameters","name":"_liquidityParameters","type":"tuple"}],"name":"addLiquidityAVAX","outputs":[{"internalType":"uint256[]","name":"depositIds","type":"uint256[]"},{"internalType":"uint256[]","name":"liquidityMinted","type":"uint256[]"}],"stateMutability":"payable","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":[],"name":"factory","outputs":[{"internalType":"contract ILBFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"getIdFromPrice","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint24","name":"_id","type":"uint24"}],"name":"getPriceFromId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"bool","name":"_swapForY","type":"bool"}],"name":"getSwapIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"feesIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"bool","name":"_swapForY","type":"bool"}],"name":"getSwapOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"feesIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oldFactory","outputs":[{"internalType":"contract IJoeFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenX","type":"address"},{"internalType":"contract IERC20","name":"_tokenY","type":"address"},{"internalType":"uint16","name":"_binStep","type":"uint16"},{"internalType":"uint256","name":"_amountXMin","type":"uint256"},{"internalType":"uint256","name":"_amountYMin","type":"uint256"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint16","name":"_binStep","type":"uint16"},{"internalType":"uint256","name":"_amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"_amountAVAXMin","type":"uint256"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"removeLiquidityAVAX","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountAVAX","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapAVAXForExactTokens","outputs":[{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactAVAXForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactAVAXForTokensSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMinAVAX","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForAVAX","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMinAVAX","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForAVAXSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountAVAXOut","type":"uint256"},{"internalType":"uint256","name":"_amountInMax","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapTokensForExactAVAX","outputs":[{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"uint256","name":"_amountInMax","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ILBToken","name":"_lbToken","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"sweepLBToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wavax","outputs":[{"internalType":"contract IWAVAX","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e06040523480156200001157600080fd5b5060405162005ae038038062005ae083398101604081905262000034916200006b565b6001600160a01b0392831660805290821660a0521660c052620000bf565b6001600160a01b03811681146200006857600080fd5b50565b6000806000606084860312156200008157600080fd5b83516200008e8162000052565b6020850151909350620000a18162000052565b6040850151909250620000b48162000052565b809150509250925092565b60805160a05160c0516159496200019760003960008181610194015281816101eb01528181610ac301528181610c3d01528181610e640152818161170a0152818161185f01528181611948015281816119db01528181611a9e01528181611b5e01528181611d1101528181611dab01528181611e3501528181612332015281816123b0015281816125610152818161263a01528181612eac0152612f2a01526000818161023c01526143200152600081816104390152818161139001528181611533015281816121510152613b7301526159496000f3fe6080604052600436106101845760003560e01c80636d3420ed116100d6578063d0e380f21161007f578063ea8f43d811610059578063ea8f43d8146104c9578063f96fe925146104dc578063fb321c701461051057600080fd5b8063d0e380f21461045b578063e324a3e41461047b578063e9361c08146104a957600080fd5b8063bcb1c957116100b0578063bcb1c957146103e7578063c22159b614610407578063c45a01551461042757600080fd5b80636d3420ed146103875780639a17e820146103a7578063a7b856d3146103c757600080fd5b806342f564a01161013857806362c067671161011257806362c0676714610327578063659ac74b146103475780636d0ff4951461036757600080fd5b806342f564a0146102d4578063440830bd146102f45780635bdd4b7c1461030757600080fd5b80632004b724116101695780632004b7241461025e578063212a1d9414610293578063264bb94e146102c157600080fd5b8063117be4c2146101d95780631bd6dfe11461022a57600080fd5b366101d457336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101d2576040516310d0bef760e31b815260040160405180910390fd5b005b600080fd5b3480156101e557600080fd5b5061020d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561023657600080fd5b5061020d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561026a57600080fd5b5061027e610279366004614bc9565b610530565b60408051928352602083019190915201610221565b34801561029f57600080fd5b506102b36102ae366004614d7a565b610839565b604051908152602001610221565b6102b36102cf366004614e0e565b610a57565b6102e76102e2366004614e0e565b610bd1565b6040516102219190614ed1565b6102b3610302366004614e0e565b610df8565b34801561031357600080fd5b5061027e610322366004614bc9565b61103d565b34801561033357600080fd5b506101d2610342366004614ee4565b61138e565b34801561035357600080fd5b5061020d610362366004614f51565b6114f4565b34801561037357600080fd5b506102b3610382366004614d7a565b6115ab565b34801561039357600080fd5b506102e76103a2366004614d7a565b61169e565b3480156103b357600080fd5b506102b36103c2366004614d7a565b6118dc565b3480156103d357600080fd5b506102e76103e2366004614d7a565b611bcc565b3480156103f357600080fd5b5061027e610402366004614fad565b611cdb565b34801561041357600080fd5b5061027e610422366004615068565b611eb3565b34801561043357600080fd5b5061020d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561046757600080fd5b506102b3610476366004615130565b611fa7565b34801561048757600080fd5b5061049b610496366004615169565b612028565b6040516102219291906151a5565b3480156104b557600080fd5b506101d26104c4366004615216565b61214f565b61049b6104d7366004615169565b612272565b3480156104e857600080fd5b506104fc6104f73660046152ab565b612482565b60405162ffffff9091168152602001610221565b34801561051c57600080fd5b506102b361052b366004614d7a565b6124f5565b6000806000856001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610573573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059791906152d7565b925050506000866001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa1580156105dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106009190615330565b905061060c81836126a8565b6040805160808101825260008082526020820181905291810182905260608101919091525b604051630157d2d160e31b815262ffffff8416600482015260009081906001600160a01b038b1690630abe9688906024016040805180830381865afa15801561067e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a2919061541c565b604080516080810182526001600160701b03938416808252939092166020830152600090820181905260608201529350151591508190506106ef575060208101516001600160701b031615155b1561078557600080806107058486888c8e612765565b919450925090506001600160701b0383111561073c57604051633d9af4e160e11b8152600481018790526024015b60405180910390fd5b8051610751906001600160801b031684615456565b61075b908b61546e565b8151909a50610773906001600160801b031688615456565b965061077f8289615456565b97505050505b861561080c57604051638f919a8360e01b815262ffffff8416600482015286151560248201526001600160a01b03891690638f919a8390604401602060405180830381865afa1580156107dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108009190615485565b62ffffff169250610631565b861561082e576040516349cda5cd60e11b815260048101889052602401610733565b505050935093915050565b600081804211156108665760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610885575080518251610882906001615456565b14155b156108a35760405163b91b4d4d60e01b815260040160405180910390fd5b60006108af8989612889565b90506000888251815181106108c6576108c66154a2565b60209081029190910101516040516370a0823160e01b81526001600160a01b038a811660048301529192506000918316906370a0823190602401602060405180830381865afa15801561091d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094191906154b8565b9050610997338460008151811061095a5761095a6154a2565b60200260200101518f8d600081518110610976576109766154a2565b60200260200101516001600160a01b031661297e909392919063ffffffff16565b6109a3838c8c8c612a3f565b6040516370a0823160e01b81526001600160a01b038a811660048301528291908416906370a0823190602401602060405180830381865afa1580156109ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1091906154b8565b610a1a919061546e565b9650868c1115610a47576040516313fab00360e21b8152600481018d905260248101889052604401610733565b5050505050509695505050505050565b60008180421115610a845760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610aa3575080518251610aa0906001615456565b14155b15610ac15760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687600081518110610afe57610afe6154a2565b60200260200101516001600160a01b031614610b585786600081518110610b2757610b276154a2565b602002602001015160405163cfec0e0160e01b815260040161073391906001600160a01b0391909116815260200190565b6000610b648989612889565b9050610b8a81600081518110610b7c57610b7c6154a2565b602002602001015134612eaa565b610b9734828b8b8b612f59565b9450848a1115610bc4576040516313fab00360e21b8152600481018b905260248101869052604401610733565b5050505095945050505050565b60608180421115610bfe5760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610c1d575080518251610c1a906001615456565b14155b15610c3b5760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687600081518110610c7857610c786154a2565b60200260200101516001600160a01b031614610ca15786600081518110610b2757610b276154a2565b6000610cad8989612889565b9050610cbb89828a8d6132da565b94503485600081518110610cd157610cd16154a2565b60200260200101511115610d1f573485600081518110610cf357610cf36154a2565b602002602001015160405163194ee21960e31b8152600401610733929190918252602082015260400190565b610d5d81600081518110610d3557610d356154a2565b602002602001015186600081518110610d5057610d506154a2565b6020026020010151612eaa565b6000610d6c828b8b898c6135c5565b90508a811015610d99576040516313fab00360e21b8152600481018c905260248101829052604401610733565b85600081518110610dac57610dac6154a2565b6020026020010151341115610dea57610dea3387600081518110610dd257610dd26154a2565b602002602001015134610de5919061546e565b613894565b505050505095945050505050565b60008180421115610e255760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610e44575080518251610e41906001615456565b14155b15610e625760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687600081518110610e9f57610e9f6154a2565b60200260200101516001600160a01b031614610ec85786600081518110610b2757610b276154a2565b6000610ed48989612889565b9050600088825181518110610eeb57610eeb6154a2565b60209081029190910101516040516370a0823160e01b81526001600160a01b038a811660048301529192506000918316906370a0823190602401602060405180830381865afa158015610f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6691906154b8565b9050610f7e83600081518110610b7c57610b7c6154a2565b610f8a838c8c8c612a3f565b6040516370a0823160e01b81526001600160a01b038a811660048301528291908416906370a0823190602401602060405180830381865afa158015610fd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff791906154b8565b611001919061546e565b9650868c111561102e576040516313fab00360e21b8152600481018d905260248101889052604401610733565b50505050505095945050505050565b6000806000806000876001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a791906152d7565b92509250925086600014806110c85750856110c4578287116110c8565b8187115b156110fd5786866110d957836110db565b825b604051637c40a4df60e01b815260048101929092526024820152604401610733565b6000886001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa15801561113e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111629190615330565b905061116e81836126a8565b60008060005b604051630157d2d160e31b815262ffffff8616600482015260009081906001600160a01b038f1690630abe9688906024016040805180830381865afa1580156111c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e5919061541c565b915091508b6111f457816111f6565b805b92505050600061120e86866000015161ffff1661391a565b905081156112cd57818c1015611224578b611226565b815b935060008b6112405761123b82866080613962565b61124c565b61124c85608084613995565b905061125886886139c7565b60006112648783613a39565b90506112708183615456565b94506001600160701b036112848587615456565b11156112a65760405163ec44eb8960e01b815260048101899052602401610733565b6112b0858d615456565b9b506112bc818c615456565b9a506112c8868f61546e565b9d5050505b8b1561135457604051638f919a8360e01b815262ffffff871660048201528b151560248201526001600160a01b038e1690638f919a8390604401602060405180830381865afa158015611324573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113489190615485565b62ffffff16955061135a565b50611360565b50611174565b8a1561137f576040516330b1335760e21b815260040160405180910390fd5b50505050505050935093915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141091906154d1565b6001600160a01b0316336001600160a01b03161461144157604051635d9515b960e11b815260040160405180910390fd5b6001600160a01b03831661146b5760001981141561145c5750475b6114668282613894565b505050565b6000198114156114e0576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156114b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114dd91906154b8565b90505b6114666001600160a01b0384168383613a89565b60405163659ac74b60e01b81526001600160a01b038581166004830152848116602483015262ffffff8416604483015261ffff831660648301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063659ac74b906084016020604051808303816000875af115801561157e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a291906154d1565b95945050505050565b600081804211156115d85760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b85858151600014806115f75750805182516115f4906001615456565b14155b156116155760405163b91b4d4d60e01b815260040160405180910390fd5b60006116218989612889565b9050611656338260008151811061163a5761163a6154a2565b60200260200101518d8b600081518110610976576109766154a2565b6116638b828b8b8b612f59565b9450848a1115611690576040516313fab00360e21b8152600481018b905260248101869052604401610733565b505050509695505050505050565b606081804211156116cb5760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b85858151600014806116ea5750805182516116e7906001615456565b14155b156117085760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687895181518110611745576117456154a2565b60200260200101516001600160a01b03161461176e5786885181518110610b2757610b276154a2565b600061177a8989612889565b905061178889828a8e6132da565b9450898560008151811061179e5761179e6154a2565b602002602001015111156117c0578985600081518110610cf357610cf36154a2565b61180d33826000815181106117d7576117d76154a2565b6020026020010151876000815181106117f2576117f26154a2565b60200260200101518b600081518110610976576109766154a2565b600061181c828b8b89306135c5565b90508b811015611849576040516313fab00360e21b8152600481018d905260248101829052604401610733565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156118ab57600080fd5b505af11580156118bf573d6000803e3d6000fd5b505050506118cd8882613894565b50505050509695505050505050565b600081804211156119095760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480611928575080518251611925906001615456565b14155b156119465760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687895181518110611983576119836154a2565b60200260200101516001600160a01b0316146119ac5786885181518110610b2757610b276154a2565b60006119b88989612889565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4691906154b8565b9050611a7b3383600081518110611a5f57611a5f6154a2565b60200260200101518e8c600081518110610976576109766154a2565b611a87828b8b30612a3f565b6040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611aed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b1191906154b8565b611b1b919061546e565b9550858b1115611b48576040516313fab00360e21b8152600481018c905260248101879052604401610733565b604051632e1a7d4d60e01b8152600481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611baa57600080fd5b505af1158015611bbe573d6000803e3d6000fd5b505050506118cd8887613894565b60608180421115611bf95760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480611c18575080518251611c15906001615456565b14155b15611c365760405163b91b4d4d60e01b815260040160405180910390fd5b6000611c428989612889565b9050611c5089828a8e6132da565b94508985600081518110611c6657611c666154a2565b60200260200101511115611c88578985600081518110610cf357610cf36154a2565b611c9f33826000815181106117d7576117d76154a2565b6000611cae828b8b898c6135c5565b90508b8110156118cd576040516313fab00360e21b8152600481018d905260248101829052604401610733565b6000808280421115611d095760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b6000611d3a8c7f00000000000000000000000000000000000000000000000000000000000000008d61ffff16613b40565b90506000816001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da091906154d1565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614905080611ddf579899985b600080611df0848e8e8e8e30613c25565b9150915082611e00578082611e03565b81815b9097509550611e1f9150506001600160a01b038e168887613a89565b604051632e1a7d4d60e01b8152600481018590527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611e8157600080fd5b505af1158015611e95573d6000803e3d6000fd5b50505050611ea38785613894565b5050509850989650505050505050565b6000808280421115611ee15760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b6000611ef28d8d8d61ffff16613b40565b90506000816001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5891906154d1565b6001600160a01b03168e6001600160a01b0316141590508015611f79579899985b611f87828c8c8c8c8c613c25565b90955093508015611f96579293925b505050995099975050505050505050565b600061201f8262ffffff16846001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa158015611ff1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120159190615330565b5161ffff1661391a565b90505b92915050565b606080600061205761203d60208601866154ee565b61204d60408701602088016154ee565b8660400135613b40565b9050806001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bb91906154d1565b6001600160a01b03166120d160208601866154ee565b6001600160a01b0316146120f85760405163b33f8ab960e01b815260040160405180910390fd5b6121203382606087013561210f60208901896154ee565b6001600160a01b031692919061297e565b61213a3382608087013561210f6040890160208a016154ee565b6121448482613d51565b909590945092505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d191906154d1565b6001600160a01b0316336001600160a01b03161461220257604051635d9515b960e11b815260040160405180910390fd5b604051633ee83b9960e21b81526001600160a01b0387169063fba0ee64906122389030908990899089908990899060040161555a565b600060405180830381600087803b15801561225257600080fd5b505af1158015612266573d6000803e3d6000fd5b50505050505050505050565b606080600061228761203d60208601866154ee565b9050806001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122eb91906154d1565b6001600160a01b031661230160208601866154ee565b6001600160a01b0316146123285760405163b33f8ab960e01b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661235f60208601866154ee565b6001600160a01b03161480156123785750348460600135145b156123a6576123878134612eaa565b6123a13382608087013561210f6040890160208a016154ee565b61213a565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166123e060408601602087016154ee565b6001600160a01b03161480156123f95750348460800135145b1561241f576124153382606087013561210f60208901896154ee565b6123a18134612eaa565b61242c60208501856154ee565b61243c60408601602087016154ee565b60405163959ceb2b60e01b81526001600160a01b03928316600482015291166024820152606085013560448201526080850135606482015234608482015260a401610733565b600061201f82846001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa1580156124c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124eb9190615330565b5161ffff166140ed565b600081804211156125225760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b858581516000148061254157508051825161253e906001615456565b14155b1561255f5760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168789518151811061259c5761259c6154a2565b60200260200101516001600160a01b0316146125c55786885181518110610b2757610b276154a2565b60006125d18989612889565b90506125ea338260008151811061163a5761163a6154a2565b6125f78b828b8b30612f59565b9450848a1115612624576040516313fab00360e21b8152600481018b905260248101869052604401610733565b604051632e1a7d4d60e01b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561268657600080fd5b505af115801561269a573d6000803e3d6000fd5b505050506116908786613894565b600082610160015164ffffffffff16426126c2919061546e565b9050826040015161ffff16811015806126e5575061016083015164ffffffffff16155b156127455762ffffff8216610140840152606083015161ffff1681101561273c5761271083610100015162ffffff16846080015161ffff16028161272b5761272b6155a7565b0462ffffff16610120840152612745565b60006101208401525b61274e42614153565b64ffffffffff1661016084015261146683836139c7565b60408051808201909152600080825260208201819052908190600061279287896000015161ffff1661391a565b905060008087156127c05760208b01516001600160701b031691506127b982608085613995565b90506127dc565b8a516001600160701b031691506127d983836080613962565b90505b6127e68a8a6139c7565b6127fa6127f38b83613a39565b8b90614183565b80519094508790612814906001600160801b031683615456565b116128245780955081945061287b565b6128316127f38b896141cf565b8051909450612849906001600160801b03168861546e565b9550876128615761285c86608085614216565b61286d565b61286d83876080614263565b94508185111561287b578194505b505050955095509592505050565b6060825167ffffffffffffffff8111156128a5576128a5614c0b565b6040519080825280602002602001820160405280156128ce578160200160208202803683370190505b509050600080836000815181106128e7576128e76154a2565b6020026020010151905060005b835181101561297557819250848160010181518110612915576129156154a2565b60200260200101519150612943868281518110612934576129346154a2565b602002602001015184846142f2565b848281518110612955576129556154a2565b6001600160a01b03909216602092830291909101909101526001016128f4565b50505092915050565b8015612a3957604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905260006129f486836143de565b905060008151118015612a18575080806020019051810190612a1691906155bd565b155b15612a365760405163197138bd60e11b815260040160405180910390fd5b50505b50505050565b600080600080600086600081518110612a5a57612a5a6154a2565b6020026020010151905060005b895181101561226657898181518110612a8257612a826154a2565b60200260200101519250888181518110612a9e57612a9e6154a2565b60200260200101519450819550878160010181518110612ac057612ac06154a2565b6020026020010151915089518160010114612af757898160010181518110612aea57612aea6154a2565b6020026020010151612af9565b865b935084612da157600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6591906155f1565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015612c9a576040516370a0823160e01b81526001600160a01b03868116600483015260009184918b16906370a0823190602401602060405180830381865afa158015612be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0591906154b8565b0390506000612c158285856144a9565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b158015612c7b57600080fd5b505af1158015612c8f573d6000803e3d6000fd5b505050505050612d9a565b6040516370a0823160e01b81526001600160a01b03868116600483015260009183918b16906370a0823190602401602060405180830381865afa158015612ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0991906154b8565b0390506000612d198284866144a9565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b158015612d7f57600080fd5b505af1158015612d93573d6000803e3d6000fd5b5050505050505b5050612ea2565b826001600160a01b03166353c059a0846001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015612dee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1291906154d1565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b03918216868316146004820152908716602482015260440160408051808303816000875af1158015612e7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9f919061541c565b50505b600101612a67565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0557600080fd5b505af1158015612f19573d6000803e3d6000fd5b50612f559350506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016915084905083613a89565b5050565b60008060008060008087600081518110612f7557612f756154a2565b602002602001015190508a955060005b8a5181101561102e578a8181518110612fa057612fa06154a2565b60200260200101519250898181518110612fbc57612fbc6154a2565b60200260200101519450819550888160010181518110612fde57612fde6154a2565b602002602001015191508a518160010114613015578a8160010181518110613008576130086154a2565b6020026020010151613017565b875b9350846131d357600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561305f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061308391906155f1565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015613142576130bf8983836144a9565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b15801561312557600080fd5b505af1158015613139573d6000803e3d6000fd5b505050506131cc565b61314d8982846144a9565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b1580156131b357600080fd5b505af11580156131c7573d6000803e3d6000fd5b505050505b50506132d2565b6000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015613213573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061323791906154d1565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af1158015613294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b8919061541c565b9150915082156132ca578099506132ce565b8199505b5050505b600101612f85565b6060825167ffffffffffffffff8111156132f6576132f6614c0b565b60405190808252806020026020018201604052801561331f578160200160208202803683370190505b5090508181855181518110613336576133366154a2565b602090810291909101015283515b80156135bc5760008461335860018461546e565b81518110613368576133686154a2565b60200260200101519050600087600184613382919061546e565b81518110613392576133926154a2565b602002602001015190506000876001856133ac919061546e565b815181106133bc576133bc6154a2565b6020026020010151905081600014156134e357600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613410573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343491906155f1565b506001600160701b031691506001600160701b0316915088868151811061345d5761345d6154a2565b60200260200101516001600160a01b0316856001600160a01b0316111561348057905b6000878781518110613494576134946154a2565b602002602001015190506134b38383836145409092919063ffffffff16565b886134bf60018a61546e565b815181106134cf576134cf6154a2565b6020026020010181815250505050506135a6565b61357c818686815181106134f9576134f96154a2565b6020026020010151856001600160a01b0316846001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356d91906154d1565b6001600160a01b03161461103d565b508561358960018761546e565b81518110613599576135996154a2565b6020026020010181815250505b50505080806135b490615636565b915050613344565b50949350505050565b600080600080600080886000815181106135e1576135e16154a2565b6020026020010151905060005b8b5181101561102e578b8181518110613609576136096154a2565b602002602001015192508a8181518110613625576136256154a2565b60200260200101519450819550898160010181518110613647576136476154a2565b602002602001015191508b51816001011461367e578b8160010181518110613671576136716154a2565b6020026020010151613680565b875b93508461378d5788816001018151811061369c5761369c6154a2565b60200260200101519650816001600160a01b0316866001600160a01b031610156137405760405163022c0d9f60e01b8152600060048201819052602482018990526001600160a01b03868116604484015260806064840152608483019190915284169063022c0d9f9060a4015b600060405180830381600087803b15801561372357600080fd5b505af1158015613737573d6000803e3d6000fd5b5050505061388c565b60405163022c0d9f60e01b8152600481018890526000602482018190526001600160a01b03868116604484015260806064840152608483019190915284169063022c0d9f9060a401613709565b6000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f191906154d1565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af115801561384e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613872919061541c565b91509150821561388457809950613888565b8199505b5050505b6001016135ee565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146138e1576040519150601f19603f3d011682016040523d82523d6000602084013e6138e6565b606091505b505090508061146657604051631722e2bb60e21b81526001600160a01b038416600482015260248101839052604401610733565b600062ffffff8311156139405760405163163d8bab60e21b815260040160405180910390fd5b627fffff19830161395a81613954856145d2565b90614618565b949350505050565b600061396f848484614263565b90506001821b80613982576139826155a7565b8385091561398e576001015b9392505050565b60006139a2848484614216565b905081806139b2576139b26155a7565b6001841b85091561398e576001019392505050565b600082610120015162ffffff166127106139f485610140015162ffffff168561487190919063ffffffff16565b6139fe919061564d565b613a089190615456565b90508260e0015162ffffff168111613a205780613a26565b8260e001515b62ffffff16610100909301929092525050565b600080613a4584614888565b90506000613a5b82670de0b6b3a764000061546e565b905080600181613a6b858861564d565b613a759190615456565b613a7f919061546e565b6115a2919061566c565b801561146657604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b1790526000613af785836143de565b905060008151118015613b1b575080806020019051810190613b1991906155bd565b155b15613b395760405163197138bd60e11b815260040160405180910390fd5b5050505050565b60405163704037bd60e01b81526001600160a01b03848116600483015283811660248301526044820183905260009182917f0000000000000000000000000000000000000000000000000000000000000000169063704037bd90606401608060405180830381865afa158015613bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bde919061568e565b6020015190506001600160a01b03811661395a57604051636b2471d160e11b81526001600160a01b0380871660048301528516602482015260448101849052606401610733565b600080876001600160a01b031663fba0ee64338a88886040518563ffffffff1660e01b8152600401613c5a9493929190615713565b600060405180830381600087803b158015613c7457600080fd5b505af1158015613c88573d6000803e3d6000fd5b5050604051630acd451d60e01b81526001600160a01b038b169250630acd451d9150613cbc90889088908890600401615751565b60408051808303816000875af1158015613cda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cfe919061541c565b909250905086821080613d1057508581105b15613d46576040516318ccfb7760e11b815260048101889052602481018390526044810187905260648101829052608401610733565b965096945050505050565b606080836101a0013580421115613d845760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b613d92610140860186615790565b9050613da2610120870187615790565b905014158015613dd05750613dbb610160860186615790565b9050613dcb610120870187615790565b905014155b15613dee5760405163b91b4d4d60e01b815260040160405180910390fd5b62ffffff60e08601351180613e0a575062ffffff610100860135115b15613e395760405163197a55c760e11b815260e086013560048201526101008601356024820152604401610733565b6000846001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e9d91906152d7565b92505050808661010001358760e00135011080613ec457508560e001358661010001358201105b15613efa57604051637d50edab60e11b815260e08701356004820152610100870135602482015260448101829052606401610733565b613f08610120870187615790565b905067ffffffffffffffff811115613f2257613f22614c0b565b604051908082528060200260200182016040528015613f4b578160200160208202803683370190505b50935060005b8451811015613fde576000613f6a610120890189615790565b83818110613f7a57613f7a6154a2565b90506020020135830190506000811280613f96575062ffffff81115b15613fb7576040516370a82e6160e11b815260048101829052602401610733565b80868381518110613fca57613fca6154a2565b602090810291909101015250600101613f51565b506000806001600160a01b03871663714c8592876140006101408c018c615790565b61400e6101608e018e615790565b8e61018001602081019061402291906154ee565b6040518763ffffffff1660e01b8152600401614043969594939291906157da565b6000604051808303816000875af1158015614062573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261408a9190810190615832565b9650909250905060a08801358210806140a657508760c0013581105b156140e2576040516318ccfb7760e11b815260a089013560048201526024810183905260c0890135604482015260648101829052608401610733565b505050509250929050565b6000806140f9836145d2565b90506000614106826148b1565b61410f866148b1565b8161411c5761411c6155a7565b05628000000190506000811280614135575062ffffff81115b1561395a5760405163163d8bab60e21b815260040160405180910390fd5b8064ffffffffff8116811461417e576040516302dfd99760e01b815260048101839052602401610733565b919050565b60408051808201909152600080825260208201526141a0826149bc565b6001600160801b0316815260c08301516127109061ffff168302046001600160801b0316602082015292915050565b6000670de0b6b3a76400006001670de0b6b3a76400006141ee86614888565b6141f8908661564d565b6142029190615456565b61420c919061546e565b61201f919061566c565b600060ff83111561423d57604051630b72ecf560e41b815260048101849052602401610733565b83831b61010084900385901c614259866001871b8685856149e9565b9695505050505050565b600060ff82111561428a57604051630b72ecf560e41b815260048101839052602401610733565b6000806142978686614a9c565b91509150816000146142a95781841c92505b80156142e9576001841b81106142dc57604051633d90990f60e01b81526004810182905260248101859052604401610733565b836101000381901b830192505b50509392505050565b6000836143d35760405163e6a4390560e01b81526001600160a01b03848116600483015283811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063e6a4390590604401602060405180830381865afa158015614367573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061438b91906154d1565b90506001600160a01b0381166143ce57604051636b2471d160e11b81526001600160a01b0380851660048301528316602482015260448101859052606401610733565b61398e565b61395a838386613b40565b6060600080846001600160a01b0316846040516143fb91906158d8565b6000604051808303816000865af19150503d8060008114614438576040519150601f19603f3d011682016040523d82523d6000602084013e61443d565b606091505b5091509150811561448257805115801561445f57506001600160a01b0385163b155b1561447d57604051635d97df8960e01b815260040160405180910390fd5b61395a565b80516144a157604051632407429160e01b815260040160405180910390fd5b805181602001fd5b6000836144c95760405163b229ed3360e01b815260040160405180910390fd5b8215806144d4575081155b156144f2576040516398c59a2960e01b815260040160405180910390fd5b6000614500856103e561564d565b9050600061450e848361564d565b905060008261451f876103e861564d565b6145299190615456565b9050614535818361566c565b979650505050505050565b6000836145605760405163b229ed3360e01b815260040160405180910390fd5b82158061456b575081155b15614589576040516398c59a2960e01b815260040160405180910390fd5b6000614595858561564d565b6145a1906103e861564d565b905060006145af868561546e565b6145bb906103e561564d565b90506145c7818361566c565b614259906001615456565b60008115806145e2575061271082115b15614603576040516374da1e1160e11b815260048101839052602401610733565b612710608083901b04600160801b0192915050565b60008080836146305750600160801b91506120229050565b50826000811215614642579015906000035b6210000081101561483257600160801b9250846001600160801b0381111561466c57911591600019045b600182161561467d5792830260801c925b800260801c60028216156146935792830260801c925b800260801c60048216156146a95792830260801c925b800260801c60088216156146bf5792830260801c925b800260801c60108216156146d55792830260801c925b800260801c60208216156146eb5792830260801c925b800260801c60408216156147015792830260801c925b8002608090811c908216156147185792830260801c925b800260801c61010082161561472f5792830260801c925b800260801c6102008216156147465792830260801c925b800260801c61040082161561475d5792830260801c925b800260801c6108008216156147745792830260801c925b800260801c61100082161561478b5792830260801c925b800260801c6120008216156147a25792830260801c925b800260801c6140008216156147b95792830260801c925b800260801c6180008216156147d05792830260801c925b800260801c620100008216156147e85792830260801c925b800260801c620200008216156148005792830260801c925b800260801c620400008216156148185792830260801c925b800260801c620800008216156148305792830260801c925b505b8261485a57604051630e9c7d6160e31b81526004810186905260248101859052604401610733565b8161486557826115a2565b6115a28360001961566c565b60008183116148825782820361201f565b50900390565b600061489382614abb565b8251602084015161ffff9182169116026402540be400020192915050565b600081600114156148c55750607f19919050565b816148e3576040516304c9fcb960e01b815260040160405180910390fd5b60019190911c9060006f80000000000000000000000000000000831061490b57506001614926565b5060001982600160fe1b81614922576149226155a7565b0492505b6000614935607f85901c614b0f565b707f80000000000000000000000000000000607f82901b16935060ff16905083811c6f8000000000000000000000000000000081146149b1576f400000000000000000000000000000005b60008113156149af57908002607f1c90600160801b82106149a7579384019360019190911c905b60011d614980565b505b50500260011b919050565b806001600160801b038116811461417e5760405163089f6cfb60e21b815260048101839052602401610733565b600081614a07578383816149ff576149ff6155a7565b0490506115a2565b838210614a315760405163656b542b60e11b81526004810183905260248101859052604401610733565b600084868809600186198101871660008190038190049091018683119095039490940294038390049390931760029290940460038102831880820284030280820284030280820284030280820284030280820284030290810290920390910292909202949350505050565b6000806000198385098385029250828110838203039150509250929050565b60008160a0015162ffffff1660001461417e576000826000015161ffff1683610100015162ffffff1602905060648360a0015162ffffff168283020260630181614b0757614b076155a7565b049392505050565b6000600160801b8210614b245750608090811c905b680100000000000000008210614b3c57604091821c91015b6401000000008210614b5057602091821c91015b620100008210614b6257601091821c91015b6101008210614b7357600891821c91015b60108210614b8357600491821c91015b60048210614b9357600291821c91015b6002821061417e57600101919050565b6001600160a01b0381168114614bb857600080fd5b50565b8015158114614bb857600080fd5b600080600060608486031215614bde57600080fd5b8335614be981614ba3565b9250602084013591506040840135614c0081614bbb565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715614c4557614c45614c0b565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614c7457614c74614c0b565b604052919050565b600067ffffffffffffffff821115614c9657614c96614c0b565b5060051b60200190565b600082601f830112614cb157600080fd5b81356020614cc6614cc183614c7c565b614c4b565b82815260059290921b84018101918181019086841115614ce557600080fd5b8286015b84811015614d005780358352918301918301614ce9565b509695505050505050565b803561417e81614ba3565b600082601f830112614d2757600080fd5b81356020614d37614cc183614c7c565b82815260059290921b84018101918181019086841115614d5657600080fd5b8286015b84811015614d00578035614d6d81614ba3565b8352918301918301614d5a565b60008060008060008060c08789031215614d9357600080fd5b8635955060208701359450604087013567ffffffffffffffff80821115614db957600080fd5b614dc58a838b01614ca0565b95506060890135915080821115614ddb57600080fd5b50614de889828a01614d16565b9350506080870135614df981614ba3565b8092505060a087013590509295509295509295565b600080600080600060a08688031215614e2657600080fd5b85359450602086013567ffffffffffffffff80821115614e4557600080fd5b614e5189838a01614ca0565b95506040880135915080821115614e6757600080fd5b50614e7488828901614d16565b9350506060860135614e8581614ba3565b949793965091946080013592915050565b600081518084526020808501945080840160005b83811015614ec657815187529582019590820190600101614eaa565b509495945050505050565b60208152600061201f6020830184614e96565b600080600060608486031215614ef957600080fd5b8335614f0481614ba3565b92506020840135614f1481614ba3565b929592945050506040919091013590565b62ffffff81168114614bb857600080fd5b61ffff81168114614bb857600080fd5b803561417e81614f36565b60008060008060808587031215614f6757600080fd5b8435614f7281614ba3565b93506020850135614f8281614ba3565b92506040850135614f9281614f25565b91506060850135614fa281614f36565b939692955090935050565b600080600080600080600080610100898b031215614fca57600080fd5b8835614fd581614ba3565b97506020890135614fe581614f36565b96506040890135955060608901359450608089013567ffffffffffffffff8082111561501057600080fd5b61501c8c838d01614ca0565b955060a08b013591508082111561503257600080fd5b5061503f8b828c01614ca0565b93505060c089013561505081614ba3565b8092505060e089013590509295985092959890939650565b60008060008060008060008060006101208a8c03121561508757600080fd5b893561509281614ba3565b985060208a01356150a281614ba3565b97506150b060408b01614f46565b965060608a0135955060808a0135945060a08a013567ffffffffffffffff808211156150db57600080fd5b6150e78d838e01614ca0565b955060c08c01359150808211156150fd57600080fd5b5061510a8c828d01614ca0565b93505061511960e08b01614d0b565b91506101008a013590509295985092959850929598565b6000806040838503121561514357600080fd5b823561514e81614ba3565b9150602083013561515e81614f25565b809150509250929050565b60006020828403121561517b57600080fd5b813567ffffffffffffffff81111561519257600080fd5b82016101c0818503121561398e57600080fd5b6040815260006151b86040830185614e96565b82810360208401526115a28185614e96565b60008083601f8401126151dc57600080fd5b50813567ffffffffffffffff8111156151f457600080fd5b6020830191508360208260051b850101111561520f57600080fd5b9250929050565b6000806000806000806080878903121561522f57600080fd5b863561523a81614ba3565b9550602087013561524a81614ba3565b9450604087013567ffffffffffffffff8082111561526757600080fd5b6152738a838b016151ca565b9096509450606089013591508082111561528c57600080fd5b5061529989828a016151ca565b979a9699509497509295939492505050565b600080604083850312156152be57600080fd5b82356152c981614ba3565b946020939093013593505050565b6000806000606084860312156152ec57600080fd5b8351925060208401519150604084015190509250925092565b805161417e81614f36565b805161417e81614f25565b805164ffffffffff8116811461417e57600080fd5b6000610180828403121561534357600080fd5b61534b614c21565b61535483615305565b815261536260208401615305565b602082015261537360408401615305565b604082015261538460608401615305565b606082015261539560808401615305565b60808201526153a660a08401615310565b60a08201526153b760c08401615305565b60c08201526153c860e08401615310565b60e08201526101006153db818501615310565b908201526101206153ed848201615310565b908201526101406153ff848201615310565b9082015261016061541184820161531b565b908201529392505050565b6000806040838503121561542f57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b6000821982111561546957615469615440565b500190565b60008282101561548057615480615440565b500390565b60006020828403121561549757600080fd5b815161398e81614f25565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156154ca57600080fd5b5051919050565b6000602082840312156154e357600080fd5b815161398e81614ba3565b60006020828403121561550057600080fd5b813561398e81614ba3565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561553d57600080fd5b8260051b8083602087013760009401602001938452509192915050565b60006001600160a01b0380891683528088166020840152506080604083015261558760808301868861550b565b828103606084015261559a81858761550b565b9998505050505050505050565b634e487b7160e01b600052601260045260246000fd5b6000602082840312156155cf57600080fd5b815161398e81614bbb565b80516001600160701b038116811461417e57600080fd5b60008060006060848603121561560657600080fd5b61560f846155da565b925061561d602085016155da565b9150604084015163ffffffff81168114614c0057600080fd5b60008161564557615645615440565b506000190190565b600081600019048311821515161561566757615667615440565b500290565b60008261568957634e487b7160e01b600052601260045260246000fd5b500490565b6000608082840312156156a057600080fd5b6040516080810181811067ffffffffffffffff821117156156c3576156c3614c0b565b60405282516156d181614f36565b815260208301516156e181614ba3565b602082015260408301516156f481614bbb565b6040820152606083015161570781614bbb565b60608201529392505050565b60006001600160a01b0380871683528086166020840152506080604083015261573f6080830185614e96565b82810360608401526145358185614e96565b6060815260006157646060830186614e96565b82810360208401526157768186614e96565b9150506001600160a01b0383166040830152949350505050565b6000808335601e198436030181126157a757600080fd5b83018035915067ffffffffffffffff8211156157c257600080fd5b6020019150600581901b360382131561520f57600080fd5b6080815260006157ed6080830189614e96565b828103602084015261580081888a61550b565b9050828103604084015261581581868861550b565b9150506001600160a01b0383166060830152979650505050505050565b60008060006060848603121561584757600080fd5b835192506020808501519250604085015167ffffffffffffffff81111561586d57600080fd5b8501601f8101871361587e57600080fd5b805161588c614cc182614c7c565b81815260059190911b820183019083810190898311156158ab57600080fd5b928401925b828410156158c9578351825292840192908401906158b0565b80955050505050509250925092565b6000825160005b818110156158f957602081860181015185830152016158df565b81811115615908576000828501525b50919091019291505056fea26469706673582212206c05eee95a8862d596ac1d3ea3c231cfdc4a1453951fddb1394e8ead624c932964736f6c634300080a00330000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa10000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7

Deployed Bytecode

0x6080604052600436106101845760003560e01c80636d3420ed116100d6578063d0e380f21161007f578063ea8f43d811610059578063ea8f43d8146104c9578063f96fe925146104dc578063fb321c701461051057600080fd5b8063d0e380f21461045b578063e324a3e41461047b578063e9361c08146104a957600080fd5b8063bcb1c957116100b0578063bcb1c957146103e7578063c22159b614610407578063c45a01551461042757600080fd5b80636d3420ed146103875780639a17e820146103a7578063a7b856d3146103c757600080fd5b806342f564a01161013857806362c067671161011257806362c0676714610327578063659ac74b146103475780636d0ff4951461036757600080fd5b806342f564a0146102d4578063440830bd146102f45780635bdd4b7c1461030757600080fd5b80632004b724116101695780632004b7241461025e578063212a1d9414610293578063264bb94e146102c157600080fd5b8063117be4c2146101d95780631bd6dfe11461022a57600080fd5b366101d457336001600160a01b037f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c716146101d2576040516310d0bef760e31b815260040160405180910390fd5b005b600080fd5b3480156101e557600080fd5b5061020d7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c781565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561023657600080fd5b5061020d7f0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa1081565b34801561026a57600080fd5b5061027e610279366004614bc9565b610530565b60408051928352602083019190915201610221565b34801561029f57600080fd5b506102b36102ae366004614d7a565b610839565b604051908152602001610221565b6102b36102cf366004614e0e565b610a57565b6102e76102e2366004614e0e565b610bd1565b6040516102219190614ed1565b6102b3610302366004614e0e565b610df8565b34801561031357600080fd5b5061027e610322366004614bc9565b61103d565b34801561033357600080fd5b506101d2610342366004614ee4565b61138e565b34801561035357600080fd5b5061020d610362366004614f51565b6114f4565b34801561037357600080fd5b506102b3610382366004614d7a565b6115ab565b34801561039357600080fd5b506102e76103a2366004614d7a565b61169e565b3480156103b357600080fd5b506102b36103c2366004614d7a565b6118dc565b3480156103d357600080fd5b506102e76103e2366004614d7a565b611bcc565b3480156103f357600080fd5b5061027e610402366004614fad565b611cdb565b34801561041357600080fd5b5061027e610422366004615068565b611eb3565b34801561043357600080fd5b5061020d7f0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef81565b34801561046757600080fd5b506102b3610476366004615130565b611fa7565b34801561048757600080fd5b5061049b610496366004615169565b612028565b6040516102219291906151a5565b3480156104b557600080fd5b506101d26104c4366004615216565b61214f565b61049b6104d7366004615169565b612272565b3480156104e857600080fd5b506104fc6104f73660046152ab565b612482565b60405162ffffff9091168152602001610221565b34801561051c57600080fd5b506102b361052b366004614d7a565b6124f5565b6000806000856001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610573573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059791906152d7565b925050506000866001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa1580156105dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106009190615330565b905061060c81836126a8565b6040805160808101825260008082526020820181905291810182905260608101919091525b604051630157d2d160e31b815262ffffff8416600482015260009081906001600160a01b038b1690630abe9688906024016040805180830381865afa15801561067e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a2919061541c565b604080516080810182526001600160701b03938416808252939092166020830152600090820181905260608201529350151591508190506106ef575060208101516001600160701b031615155b1561078557600080806107058486888c8e612765565b919450925090506001600160701b0383111561073c57604051633d9af4e160e11b8152600481018790526024015b60405180910390fd5b8051610751906001600160801b031684615456565b61075b908b61546e565b8151909a50610773906001600160801b031688615456565b965061077f8289615456565b97505050505b861561080c57604051638f919a8360e01b815262ffffff8416600482015286151560248201526001600160a01b03891690638f919a8390604401602060405180830381865afa1580156107dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108009190615485565b62ffffff169250610631565b861561082e576040516349cda5cd60e11b815260048101889052602401610733565b505050935093915050565b600081804211156108665760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610885575080518251610882906001615456565b14155b156108a35760405163b91b4d4d60e01b815260040160405180910390fd5b60006108af8989612889565b90506000888251815181106108c6576108c66154a2565b60209081029190910101516040516370a0823160e01b81526001600160a01b038a811660048301529192506000918316906370a0823190602401602060405180830381865afa15801561091d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094191906154b8565b9050610997338460008151811061095a5761095a6154a2565b60200260200101518f8d600081518110610976576109766154a2565b60200260200101516001600160a01b031661297e909392919063ffffffff16565b6109a3838c8c8c612a3f565b6040516370a0823160e01b81526001600160a01b038a811660048301528291908416906370a0823190602401602060405180830381865afa1580156109ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1091906154b8565b610a1a919061546e565b9650868c1115610a47576040516313fab00360e21b8152600481018d905260248101889052604401610733565b5050505050509695505050505050565b60008180421115610a845760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610aa3575080518251610aa0906001615456565b14155b15610ac15760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031687600081518110610afe57610afe6154a2565b60200260200101516001600160a01b031614610b585786600081518110610b2757610b276154a2565b602002602001015160405163cfec0e0160e01b815260040161073391906001600160a01b0391909116815260200190565b6000610b648989612889565b9050610b8a81600081518110610b7c57610b7c6154a2565b602002602001015134612eaa565b610b9734828b8b8b612f59565b9450848a1115610bc4576040516313fab00360e21b8152600481018b905260248101869052604401610733565b5050505095945050505050565b60608180421115610bfe5760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610c1d575080518251610c1a906001615456565b14155b15610c3b5760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031687600081518110610c7857610c786154a2565b60200260200101516001600160a01b031614610ca15786600081518110610b2757610b276154a2565b6000610cad8989612889565b9050610cbb89828a8d6132da565b94503485600081518110610cd157610cd16154a2565b60200260200101511115610d1f573485600081518110610cf357610cf36154a2565b602002602001015160405163194ee21960e31b8152600401610733929190918252602082015260400190565b610d5d81600081518110610d3557610d356154a2565b602002602001015186600081518110610d5057610d506154a2565b6020026020010151612eaa565b6000610d6c828b8b898c6135c5565b90508a811015610d99576040516313fab00360e21b8152600481018c905260248101829052604401610733565b85600081518110610dac57610dac6154a2565b6020026020010151341115610dea57610dea3387600081518110610dd257610dd26154a2565b602002602001015134610de5919061546e565b613894565b505050505095945050505050565b60008180421115610e255760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610e44575080518251610e41906001615456565b14155b15610e625760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031687600081518110610e9f57610e9f6154a2565b60200260200101516001600160a01b031614610ec85786600081518110610b2757610b276154a2565b6000610ed48989612889565b9050600088825181518110610eeb57610eeb6154a2565b60209081029190910101516040516370a0823160e01b81526001600160a01b038a811660048301529192506000918316906370a0823190602401602060405180830381865afa158015610f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6691906154b8565b9050610f7e83600081518110610b7c57610b7c6154a2565b610f8a838c8c8c612a3f565b6040516370a0823160e01b81526001600160a01b038a811660048301528291908416906370a0823190602401602060405180830381865afa158015610fd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff791906154b8565b611001919061546e565b9650868c111561102e576040516313fab00360e21b8152600481018d905260248101889052604401610733565b50505050505095945050505050565b6000806000806000876001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a791906152d7565b92509250925086600014806110c85750856110c4578287116110c8565b8187115b156110fd5786866110d957836110db565b825b604051637c40a4df60e01b815260048101929092526024820152604401610733565b6000886001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa15801561113e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111629190615330565b905061116e81836126a8565b60008060005b604051630157d2d160e31b815262ffffff8616600482015260009081906001600160a01b038f1690630abe9688906024016040805180830381865afa1580156111c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e5919061541c565b915091508b6111f457816111f6565b805b92505050600061120e86866000015161ffff1661391a565b905081156112cd57818c1015611224578b611226565b815b935060008b6112405761123b82866080613962565b61124c565b61124c85608084613995565b905061125886886139c7565b60006112648783613a39565b90506112708183615456565b94506001600160701b036112848587615456565b11156112a65760405163ec44eb8960e01b815260048101899052602401610733565b6112b0858d615456565b9b506112bc818c615456565b9a506112c8868f61546e565b9d5050505b8b1561135457604051638f919a8360e01b815262ffffff871660048201528b151560248201526001600160a01b038e1690638f919a8390604401602060405180830381865afa158015611324573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113489190615485565b62ffffff16955061135a565b50611360565b50611174565b8a1561137f576040516330b1335760e21b815260040160405180910390fd5b50505050505050935093915050565b7f0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141091906154d1565b6001600160a01b0316336001600160a01b03161461144157604051635d9515b960e11b815260040160405180910390fd5b6001600160a01b03831661146b5760001981141561145c5750475b6114668282613894565b505050565b6000198114156114e0576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156114b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114dd91906154b8565b90505b6114666001600160a01b0384168383613a89565b60405163659ac74b60e01b81526001600160a01b038581166004830152848116602483015262ffffff8416604483015261ffff831660648301526000917f0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef9091169063659ac74b906084016020604051808303816000875af115801561157e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a291906154d1565b95945050505050565b600081804211156115d85760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b85858151600014806115f75750805182516115f4906001615456565b14155b156116155760405163b91b4d4d60e01b815260040160405180910390fd5b60006116218989612889565b9050611656338260008151811061163a5761163a6154a2565b60200260200101518d8b600081518110610976576109766154a2565b6116638b828b8b8b612f59565b9450848a1115611690576040516313fab00360e21b8152600481018b905260248101869052604401610733565b505050509695505050505050565b606081804211156116cb5760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b85858151600014806116ea5750805182516116e7906001615456565b14155b156117085760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031687895181518110611745576117456154a2565b60200260200101516001600160a01b03161461176e5786885181518110610b2757610b276154a2565b600061177a8989612889565b905061178889828a8e6132da565b9450898560008151811061179e5761179e6154a2565b602002602001015111156117c0578985600081518110610cf357610cf36154a2565b61180d33826000815181106117d7576117d76154a2565b6020026020010151876000815181106117f2576117f26154a2565b60200260200101518b600081518110610976576109766154a2565b600061181c828b8b89306135c5565b90508b811015611849576040516313fab00360e21b8152600481018d905260248101829052604401610733565b604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156118ab57600080fd5b505af11580156118bf573d6000803e3d6000fd5b505050506118cd8882613894565b50505050509695505050505050565b600081804211156119095760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480611928575080518251611925906001615456565b14155b156119465760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031687895181518110611983576119836154a2565b60200260200101516001600160a01b0316146119ac5786885181518110610b2757610b276154a2565b60006119b88989612889565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c716906370a0823190602401602060405180830381865afa158015611a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4691906154b8565b9050611a7b3383600081518110611a5f57611a5f6154a2565b60200260200101518e8c600081518110610976576109766154a2565b611a87828b8b30612a3f565b6040516370a0823160e01b815230600482015281907f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b0316906370a0823190602401602060405180830381865afa158015611aed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b1191906154b8565b611b1b919061546e565b9550858b1115611b48576040516313fab00360e21b8152600481018c905260248101879052604401610733565b604051632e1a7d4d60e01b8152600481018790527f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611baa57600080fd5b505af1158015611bbe573d6000803e3d6000fd5b505050506118cd8887613894565b60608180421115611bf95760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480611c18575080518251611c15906001615456565b14155b15611c365760405163b91b4d4d60e01b815260040160405180910390fd5b6000611c428989612889565b9050611c5089828a8e6132da565b94508985600081518110611c6657611c666154a2565b60200260200101511115611c88578985600081518110610cf357610cf36154a2565b611c9f33826000815181106117d7576117d76154a2565b6000611cae828b8b898c6135c5565b90508b8110156118cd576040516313fab00360e21b8152600481018d905260248101829052604401610733565b6000808280421115611d095760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b6000611d3a8c7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c78d61ffff16613b40565b90506000816001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da091906154d1565b6001600160a01b03167f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031614905080611ddf579899985b600080611df0848e8e8e8e30613c25565b9150915082611e00578082611e03565b81815b9097509550611e1f9150506001600160a01b038e168887613a89565b604051632e1a7d4d60e01b8152600481018590527f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611e8157600080fd5b505af1158015611e95573d6000803e3d6000fd5b50505050611ea38785613894565b5050509850989650505050505050565b6000808280421115611ee15760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b6000611ef28d8d8d61ffff16613b40565b90506000816001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5891906154d1565b6001600160a01b03168e6001600160a01b0316141590508015611f79579899985b611f87828c8c8c8c8c613c25565b90955093508015611f96579293925b505050995099975050505050505050565b600061201f8262ffffff16846001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa158015611ff1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120159190615330565b5161ffff1661391a565b90505b92915050565b606080600061205761203d60208601866154ee565b61204d60408701602088016154ee565b8660400135613b40565b9050806001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bb91906154d1565b6001600160a01b03166120d160208601866154ee565b6001600160a01b0316146120f85760405163b33f8ab960e01b815260040160405180910390fd5b6121203382606087013561210f60208901896154ee565b6001600160a01b031692919061297e565b61213a3382608087013561210f6040890160208a016154ee565b6121448482613d51565b909590945092505050565b7f0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d191906154d1565b6001600160a01b0316336001600160a01b03161461220257604051635d9515b960e11b815260040160405180910390fd5b604051633ee83b9960e21b81526001600160a01b0387169063fba0ee64906122389030908990899089908990899060040161555a565b600060405180830381600087803b15801561225257600080fd5b505af1158015612266573d6000803e3d6000fd5b50505050505050505050565b606080600061228761203d60208601866154ee565b9050806001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122eb91906154d1565b6001600160a01b031661230160208601866154ee565b6001600160a01b0316146123285760405163b33f8ab960e01b815260040160405180910390fd5b6001600160a01b037f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c71661235f60208601866154ee565b6001600160a01b03161480156123785750348460600135145b156123a6576123878134612eaa565b6123a13382608087013561210f6040890160208a016154ee565b61213a565b6001600160a01b037f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7166123e060408601602087016154ee565b6001600160a01b03161480156123f95750348460800135145b1561241f576124153382606087013561210f60208901896154ee565b6123a18134612eaa565b61242c60208501856154ee565b61243c60408601602087016154ee565b60405163959ceb2b60e01b81526001600160a01b03928316600482015291166024820152606085013560448201526080850135606482015234608482015260a401610733565b600061201f82846001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa1580156124c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124eb9190615330565b5161ffff166140ed565b600081804211156125225760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b858581516000148061254157508051825161253e906001615456565b14155b1561255f5760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b03168789518151811061259c5761259c6154a2565b60200260200101516001600160a01b0316146125c55786885181518110610b2757610b276154a2565b60006125d18989612889565b90506125ea338260008151811061163a5761163a6154a2565b6125f78b828b8b30612f59565b9450848a1115612624576040516313fab00360e21b8152600481018b905260248101869052604401610733565b604051632e1a7d4d60e01b8152600481018690527f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561268657600080fd5b505af115801561269a573d6000803e3d6000fd5b505050506116908786613894565b600082610160015164ffffffffff16426126c2919061546e565b9050826040015161ffff16811015806126e5575061016083015164ffffffffff16155b156127455762ffffff8216610140840152606083015161ffff1681101561273c5761271083610100015162ffffff16846080015161ffff16028161272b5761272b6155a7565b0462ffffff16610120840152612745565b60006101208401525b61274e42614153565b64ffffffffff1661016084015261146683836139c7565b60408051808201909152600080825260208201819052908190600061279287896000015161ffff1661391a565b905060008087156127c05760208b01516001600160701b031691506127b982608085613995565b90506127dc565b8a516001600160701b031691506127d983836080613962565b90505b6127e68a8a6139c7565b6127fa6127f38b83613a39565b8b90614183565b80519094508790612814906001600160801b031683615456565b116128245780955081945061287b565b6128316127f38b896141cf565b8051909450612849906001600160801b03168861546e565b9550876128615761285c86608085614216565b61286d565b61286d83876080614263565b94508185111561287b578194505b505050955095509592505050565b6060825167ffffffffffffffff8111156128a5576128a5614c0b565b6040519080825280602002602001820160405280156128ce578160200160208202803683370190505b509050600080836000815181106128e7576128e76154a2565b6020026020010151905060005b835181101561297557819250848160010181518110612915576129156154a2565b60200260200101519150612943868281518110612934576129346154a2565b602002602001015184846142f2565b848281518110612955576129556154a2565b6001600160a01b03909216602092830291909101909101526001016128f4565b50505092915050565b8015612a3957604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905260006129f486836143de565b905060008151118015612a18575080806020019051810190612a1691906155bd565b155b15612a365760405163197138bd60e11b815260040160405180910390fd5b50505b50505050565b600080600080600086600081518110612a5a57612a5a6154a2565b6020026020010151905060005b895181101561226657898181518110612a8257612a826154a2565b60200260200101519250888181518110612a9e57612a9e6154a2565b60200260200101519450819550878160010181518110612ac057612ac06154a2565b6020026020010151915089518160010114612af757898160010181518110612aea57612aea6154a2565b6020026020010151612af9565b865b935084612da157600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6591906155f1565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015612c9a576040516370a0823160e01b81526001600160a01b03868116600483015260009184918b16906370a0823190602401602060405180830381865afa158015612be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0591906154b8565b0390506000612c158285856144a9565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b158015612c7b57600080fd5b505af1158015612c8f573d6000803e3d6000fd5b505050505050612d9a565b6040516370a0823160e01b81526001600160a01b03868116600483015260009183918b16906370a0823190602401602060405180830381865afa158015612ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0991906154b8565b0390506000612d198284866144a9565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b158015612d7f57600080fd5b505af1158015612d93573d6000803e3d6000fd5b5050505050505b5050612ea2565b826001600160a01b03166353c059a0846001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015612dee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1291906154d1565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b03918216868316146004820152908716602482015260440160408051808303816000875af1158015612e7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9f919061541c565b50505b600101612a67565b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0557600080fd5b505af1158015612f19573d6000803e3d6000fd5b50612f559350506001600160a01b037f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c716915084905083613a89565b5050565b60008060008060008087600081518110612f7557612f756154a2565b602002602001015190508a955060005b8a5181101561102e578a8181518110612fa057612fa06154a2565b60200260200101519250898181518110612fbc57612fbc6154a2565b60200260200101519450819550888160010181518110612fde57612fde6154a2565b602002602001015191508a518160010114613015578a8160010181518110613008576130086154a2565b6020026020010151613017565b875b9350846131d357600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561305f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061308391906155f1565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015613142576130bf8983836144a9565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b15801561312557600080fd5b505af1158015613139573d6000803e3d6000fd5b505050506131cc565b61314d8982846144a9565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b1580156131b357600080fd5b505af11580156131c7573d6000803e3d6000fd5b505050505b50506132d2565b6000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015613213573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061323791906154d1565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af1158015613294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b8919061541c565b9150915082156132ca578099506132ce565b8199505b5050505b600101612f85565b6060825167ffffffffffffffff8111156132f6576132f6614c0b565b60405190808252806020026020018201604052801561331f578160200160208202803683370190505b5090508181855181518110613336576133366154a2565b602090810291909101015283515b80156135bc5760008461335860018461546e565b81518110613368576133686154a2565b60200260200101519050600087600184613382919061546e565b81518110613392576133926154a2565b602002602001015190506000876001856133ac919061546e565b815181106133bc576133bc6154a2565b6020026020010151905081600014156134e357600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613410573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343491906155f1565b506001600160701b031691506001600160701b0316915088868151811061345d5761345d6154a2565b60200260200101516001600160a01b0316856001600160a01b0316111561348057905b6000878781518110613494576134946154a2565b602002602001015190506134b38383836145409092919063ffffffff16565b886134bf60018a61546e565b815181106134cf576134cf6154a2565b6020026020010181815250505050506135a6565b61357c818686815181106134f9576134f96154a2565b6020026020010151856001600160a01b0316846001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356d91906154d1565b6001600160a01b03161461103d565b508561358960018761546e565b81518110613599576135996154a2565b6020026020010181815250505b50505080806135b490615636565b915050613344565b50949350505050565b600080600080600080886000815181106135e1576135e16154a2565b6020026020010151905060005b8b5181101561102e578b8181518110613609576136096154a2565b602002602001015192508a8181518110613625576136256154a2565b60200260200101519450819550898160010181518110613647576136476154a2565b602002602001015191508b51816001011461367e578b8160010181518110613671576136716154a2565b6020026020010151613680565b875b93508461378d5788816001018151811061369c5761369c6154a2565b60200260200101519650816001600160a01b0316866001600160a01b031610156137405760405163022c0d9f60e01b8152600060048201819052602482018990526001600160a01b03868116604484015260806064840152608483019190915284169063022c0d9f9060a4015b600060405180830381600087803b15801561372357600080fd5b505af1158015613737573d6000803e3d6000fd5b5050505061388c565b60405163022c0d9f60e01b8152600481018890526000602482018190526001600160a01b03868116604484015260806064840152608483019190915284169063022c0d9f9060a401613709565b6000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f191906154d1565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af115801561384e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613872919061541c565b91509150821561388457809950613888565b8199505b5050505b6001016135ee565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146138e1576040519150601f19603f3d011682016040523d82523d6000602084013e6138e6565b606091505b505090508061146657604051631722e2bb60e21b81526001600160a01b038416600482015260248101839052604401610733565b600062ffffff8311156139405760405163163d8bab60e21b815260040160405180910390fd5b627fffff19830161395a81613954856145d2565b90614618565b949350505050565b600061396f848484614263565b90506001821b80613982576139826155a7565b8385091561398e576001015b9392505050565b60006139a2848484614216565b905081806139b2576139b26155a7565b6001841b85091561398e576001019392505050565b600082610120015162ffffff166127106139f485610140015162ffffff168561487190919063ffffffff16565b6139fe919061564d565b613a089190615456565b90508260e0015162ffffff168111613a205780613a26565b8260e001515b62ffffff16610100909301929092525050565b600080613a4584614888565b90506000613a5b82670de0b6b3a764000061546e565b905080600181613a6b858861564d565b613a759190615456565b613a7f919061546e565b6115a2919061566c565b801561146657604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b1790526000613af785836143de565b905060008151118015613b1b575080806020019051810190613b1991906155bd565b155b15613b395760405163197138bd60e11b815260040160405180910390fd5b5050505050565b60405163704037bd60e01b81526001600160a01b03848116600483015283811660248301526044820183905260009182917f0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef169063704037bd90606401608060405180830381865afa158015613bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bde919061568e565b6020015190506001600160a01b03811661395a57604051636b2471d160e11b81526001600160a01b0380871660048301528516602482015260448101849052606401610733565b600080876001600160a01b031663fba0ee64338a88886040518563ffffffff1660e01b8152600401613c5a9493929190615713565b600060405180830381600087803b158015613c7457600080fd5b505af1158015613c88573d6000803e3d6000fd5b5050604051630acd451d60e01b81526001600160a01b038b169250630acd451d9150613cbc90889088908890600401615751565b60408051808303816000875af1158015613cda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cfe919061541c565b909250905086821080613d1057508581105b15613d46576040516318ccfb7760e11b815260048101889052602481018390526044810187905260648101829052608401610733565b965096945050505050565b606080836101a0013580421115613d845760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b613d92610140860186615790565b9050613da2610120870187615790565b905014158015613dd05750613dbb610160860186615790565b9050613dcb610120870187615790565b905014155b15613dee5760405163b91b4d4d60e01b815260040160405180910390fd5b62ffffff60e08601351180613e0a575062ffffff610100860135115b15613e395760405163197a55c760e11b815260e086013560048201526101008601356024820152604401610733565b6000846001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e9d91906152d7565b92505050808661010001358760e00135011080613ec457508560e001358661010001358201105b15613efa57604051637d50edab60e11b815260e08701356004820152610100870135602482015260448101829052606401610733565b613f08610120870187615790565b905067ffffffffffffffff811115613f2257613f22614c0b565b604051908082528060200260200182016040528015613f4b578160200160208202803683370190505b50935060005b8451811015613fde576000613f6a610120890189615790565b83818110613f7a57613f7a6154a2565b90506020020135830190506000811280613f96575062ffffff81115b15613fb7576040516370a82e6160e11b815260048101829052602401610733565b80868381518110613fca57613fca6154a2565b602090810291909101015250600101613f51565b506000806001600160a01b03871663714c8592876140006101408c018c615790565b61400e6101608e018e615790565b8e61018001602081019061402291906154ee565b6040518763ffffffff1660e01b8152600401614043969594939291906157da565b6000604051808303816000875af1158015614062573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261408a9190810190615832565b9650909250905060a08801358210806140a657508760c0013581105b156140e2576040516318ccfb7760e11b815260a089013560048201526024810183905260c0890135604482015260648101829052608401610733565b505050509250929050565b6000806140f9836145d2565b90506000614106826148b1565b61410f866148b1565b8161411c5761411c6155a7565b05628000000190506000811280614135575062ffffff81115b1561395a5760405163163d8bab60e21b815260040160405180910390fd5b8064ffffffffff8116811461417e576040516302dfd99760e01b815260048101839052602401610733565b919050565b60408051808201909152600080825260208201526141a0826149bc565b6001600160801b0316815260c08301516127109061ffff168302046001600160801b0316602082015292915050565b6000670de0b6b3a76400006001670de0b6b3a76400006141ee86614888565b6141f8908661564d565b6142029190615456565b61420c919061546e565b61201f919061566c565b600060ff83111561423d57604051630b72ecf560e41b815260048101849052602401610733565b83831b61010084900385901c614259866001871b8685856149e9565b9695505050505050565b600060ff82111561428a57604051630b72ecf560e41b815260048101839052602401610733565b6000806142978686614a9c565b91509150816000146142a95781841c92505b80156142e9576001841b81106142dc57604051633d90990f60e01b81526004810182905260248101859052604401610733565b836101000381901b830192505b50509392505050565b6000836143d35760405163e6a4390560e01b81526001600160a01b03848116600483015283811660248301527f0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa10169063e6a4390590604401602060405180830381865afa158015614367573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061438b91906154d1565b90506001600160a01b0381166143ce57604051636b2471d160e11b81526001600160a01b0380851660048301528316602482015260448101859052606401610733565b61398e565b61395a838386613b40565b6060600080846001600160a01b0316846040516143fb91906158d8565b6000604051808303816000865af19150503d8060008114614438576040519150601f19603f3d011682016040523d82523d6000602084013e61443d565b606091505b5091509150811561448257805115801561445f57506001600160a01b0385163b155b1561447d57604051635d97df8960e01b815260040160405180910390fd5b61395a565b80516144a157604051632407429160e01b815260040160405180910390fd5b805181602001fd5b6000836144c95760405163b229ed3360e01b815260040160405180910390fd5b8215806144d4575081155b156144f2576040516398c59a2960e01b815260040160405180910390fd5b6000614500856103e561564d565b9050600061450e848361564d565b905060008261451f876103e861564d565b6145299190615456565b9050614535818361566c565b979650505050505050565b6000836145605760405163b229ed3360e01b815260040160405180910390fd5b82158061456b575081155b15614589576040516398c59a2960e01b815260040160405180910390fd5b6000614595858561564d565b6145a1906103e861564d565b905060006145af868561546e565b6145bb906103e561564d565b90506145c7818361566c565b614259906001615456565b60008115806145e2575061271082115b15614603576040516374da1e1160e11b815260048101839052602401610733565b612710608083901b04600160801b0192915050565b60008080836146305750600160801b91506120229050565b50826000811215614642579015906000035b6210000081101561483257600160801b9250846001600160801b0381111561466c57911591600019045b600182161561467d5792830260801c925b800260801c60028216156146935792830260801c925b800260801c60048216156146a95792830260801c925b800260801c60088216156146bf5792830260801c925b800260801c60108216156146d55792830260801c925b800260801c60208216156146eb5792830260801c925b800260801c60408216156147015792830260801c925b8002608090811c908216156147185792830260801c925b800260801c61010082161561472f5792830260801c925b800260801c6102008216156147465792830260801c925b800260801c61040082161561475d5792830260801c925b800260801c6108008216156147745792830260801c925b800260801c61100082161561478b5792830260801c925b800260801c6120008216156147a25792830260801c925b800260801c6140008216156147b95792830260801c925b800260801c6180008216156147d05792830260801c925b800260801c620100008216156147e85792830260801c925b800260801c620200008216156148005792830260801c925b800260801c620400008216156148185792830260801c925b800260801c620800008216156148305792830260801c925b505b8261485a57604051630e9c7d6160e31b81526004810186905260248101859052604401610733565b8161486557826115a2565b6115a28360001961566c565b60008183116148825782820361201f565b50900390565b600061489382614abb565b8251602084015161ffff9182169116026402540be400020192915050565b600081600114156148c55750607f19919050565b816148e3576040516304c9fcb960e01b815260040160405180910390fd5b60019190911c9060006f80000000000000000000000000000000831061490b57506001614926565b5060001982600160fe1b81614922576149226155a7565b0492505b6000614935607f85901c614b0f565b707f80000000000000000000000000000000607f82901b16935060ff16905083811c6f8000000000000000000000000000000081146149b1576f400000000000000000000000000000005b60008113156149af57908002607f1c90600160801b82106149a7579384019360019190911c905b60011d614980565b505b50500260011b919050565b806001600160801b038116811461417e5760405163089f6cfb60e21b815260048101839052602401610733565b600081614a07578383816149ff576149ff6155a7565b0490506115a2565b838210614a315760405163656b542b60e11b81526004810183905260248101859052604401610733565b600084868809600186198101871660008190038190049091018683119095039490940294038390049390931760029290940460038102831880820284030280820284030280820284030280820284030280820284030290810290920390910292909202949350505050565b6000806000198385098385029250828110838203039150509250929050565b60008160a0015162ffffff1660001461417e576000826000015161ffff1683610100015162ffffff1602905060648360a0015162ffffff168283020260630181614b0757614b076155a7565b049392505050565b6000600160801b8210614b245750608090811c905b680100000000000000008210614b3c57604091821c91015b6401000000008210614b5057602091821c91015b620100008210614b6257601091821c91015b6101008210614b7357600891821c91015b60108210614b8357600491821c91015b60048210614b9357600291821c91015b6002821061417e57600101919050565b6001600160a01b0381168114614bb857600080fd5b50565b8015158114614bb857600080fd5b600080600060608486031215614bde57600080fd5b8335614be981614ba3565b9250602084013591506040840135614c0081614bbb565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715614c4557614c45614c0b565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614c7457614c74614c0b565b604052919050565b600067ffffffffffffffff821115614c9657614c96614c0b565b5060051b60200190565b600082601f830112614cb157600080fd5b81356020614cc6614cc183614c7c565b614c4b565b82815260059290921b84018101918181019086841115614ce557600080fd5b8286015b84811015614d005780358352918301918301614ce9565b509695505050505050565b803561417e81614ba3565b600082601f830112614d2757600080fd5b81356020614d37614cc183614c7c565b82815260059290921b84018101918181019086841115614d5657600080fd5b8286015b84811015614d00578035614d6d81614ba3565b8352918301918301614d5a565b60008060008060008060c08789031215614d9357600080fd5b8635955060208701359450604087013567ffffffffffffffff80821115614db957600080fd5b614dc58a838b01614ca0565b95506060890135915080821115614ddb57600080fd5b50614de889828a01614d16565b9350506080870135614df981614ba3565b8092505060a087013590509295509295509295565b600080600080600060a08688031215614e2657600080fd5b85359450602086013567ffffffffffffffff80821115614e4557600080fd5b614e5189838a01614ca0565b95506040880135915080821115614e6757600080fd5b50614e7488828901614d16565b9350506060860135614e8581614ba3565b949793965091946080013592915050565b600081518084526020808501945080840160005b83811015614ec657815187529582019590820190600101614eaa565b509495945050505050565b60208152600061201f6020830184614e96565b600080600060608486031215614ef957600080fd5b8335614f0481614ba3565b92506020840135614f1481614ba3565b929592945050506040919091013590565b62ffffff81168114614bb857600080fd5b61ffff81168114614bb857600080fd5b803561417e81614f36565b60008060008060808587031215614f6757600080fd5b8435614f7281614ba3565b93506020850135614f8281614ba3565b92506040850135614f9281614f25565b91506060850135614fa281614f36565b939692955090935050565b600080600080600080600080610100898b031215614fca57600080fd5b8835614fd581614ba3565b97506020890135614fe581614f36565b96506040890135955060608901359450608089013567ffffffffffffffff8082111561501057600080fd5b61501c8c838d01614ca0565b955060a08b013591508082111561503257600080fd5b5061503f8b828c01614ca0565b93505060c089013561505081614ba3565b8092505060e089013590509295985092959890939650565b60008060008060008060008060006101208a8c03121561508757600080fd5b893561509281614ba3565b985060208a01356150a281614ba3565b97506150b060408b01614f46565b965060608a0135955060808a0135945060a08a013567ffffffffffffffff808211156150db57600080fd5b6150e78d838e01614ca0565b955060c08c01359150808211156150fd57600080fd5b5061510a8c828d01614ca0565b93505061511960e08b01614d0b565b91506101008a013590509295985092959850929598565b6000806040838503121561514357600080fd5b823561514e81614ba3565b9150602083013561515e81614f25565b809150509250929050565b60006020828403121561517b57600080fd5b813567ffffffffffffffff81111561519257600080fd5b82016101c0818503121561398e57600080fd5b6040815260006151b86040830185614e96565b82810360208401526115a28185614e96565b60008083601f8401126151dc57600080fd5b50813567ffffffffffffffff8111156151f457600080fd5b6020830191508360208260051b850101111561520f57600080fd5b9250929050565b6000806000806000806080878903121561522f57600080fd5b863561523a81614ba3565b9550602087013561524a81614ba3565b9450604087013567ffffffffffffffff8082111561526757600080fd5b6152738a838b016151ca565b9096509450606089013591508082111561528c57600080fd5b5061529989828a016151ca565b979a9699509497509295939492505050565b600080604083850312156152be57600080fd5b82356152c981614ba3565b946020939093013593505050565b6000806000606084860312156152ec57600080fd5b8351925060208401519150604084015190509250925092565b805161417e81614f36565b805161417e81614f25565b805164ffffffffff8116811461417e57600080fd5b6000610180828403121561534357600080fd5b61534b614c21565b61535483615305565b815261536260208401615305565b602082015261537360408401615305565b604082015261538460608401615305565b606082015261539560808401615305565b60808201526153a660a08401615310565b60a08201526153b760c08401615305565b60c08201526153c860e08401615310565b60e08201526101006153db818501615310565b908201526101206153ed848201615310565b908201526101406153ff848201615310565b9082015261016061541184820161531b565b908201529392505050565b6000806040838503121561542f57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b6000821982111561546957615469615440565b500190565b60008282101561548057615480615440565b500390565b60006020828403121561549757600080fd5b815161398e81614f25565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156154ca57600080fd5b5051919050565b6000602082840312156154e357600080fd5b815161398e81614ba3565b60006020828403121561550057600080fd5b813561398e81614ba3565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561553d57600080fd5b8260051b8083602087013760009401602001938452509192915050565b60006001600160a01b0380891683528088166020840152506080604083015261558760808301868861550b565b828103606084015261559a81858761550b565b9998505050505050505050565b634e487b7160e01b600052601260045260246000fd5b6000602082840312156155cf57600080fd5b815161398e81614bbb565b80516001600160701b038116811461417e57600080fd5b60008060006060848603121561560657600080fd5b61560f846155da565b925061561d602085016155da565b9150604084015163ffffffff81168114614c0057600080fd5b60008161564557615645615440565b506000190190565b600081600019048311821515161561566757615667615440565b500290565b60008261568957634e487b7160e01b600052601260045260246000fd5b500490565b6000608082840312156156a057600080fd5b6040516080810181811067ffffffffffffffff821117156156c3576156c3614c0b565b60405282516156d181614f36565b815260208301516156e181614ba3565b602082015260408301516156f481614bbb565b6040820152606083015161570781614bbb565b60608201529392505050565b60006001600160a01b0380871683528086166020840152506080604083015261573f6080830185614e96565b82810360608401526145358185614e96565b6060815260006157646060830186614e96565b82810360208401526157768186614e96565b9150506001600160a01b0383166040830152949350505050565b6000808335601e198436030181126157a757600080fd5b83018035915067ffffffffffffffff8211156157c257600080fd5b6020019150600581901b360382131561520f57600080fd5b6080815260006157ed6080830189614e96565b828103602084015261580081888a61550b565b9050828103604084015261581581868861550b565b9150506001600160a01b0383166060830152979650505050505050565b60008060006060848603121561584757600080fd5b835192506020808501519250604085015167ffffffffffffffff81111561586d57600080fd5b8501601f8101871361587e57600080fd5b805161588c614cc182614c7c565b81815260059190911b820183019083810190898311156158ab57600080fd5b928401925b828410156158c9578351825292840192908401906158b0565b80955050505050509250925092565b6000825160005b818110156158f957602081860181015185830152016158df565b81811115615908576000828501525b50919091019291505056fea26469706673582212206c05eee95a8862d596ac1d3ea3c231cfdc4a1453951fddb1394e8ead624c932964736f6c634300080a0033

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

0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa10000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7

-----Decoded View---------------
Arg [0] : _factory (address): 0x6E77932A92582f504FF6c4BdbCef7Da6c198aEEf
Arg [1] : _oldFactory (address): 0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10
Arg [2] : _wavax (address): 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef
Arg [1] : 0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa10
Arg [2] : 000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7


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

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

OVERVIEW

One-stop-shop decentralized trading on Avalanche.

Loading...
Loading

Validator Index Block Amount
View All Withdrawals

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

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